2021-07-30 07:41:02 +02:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
2021-10-30 12:48:39 +02:00
|
|
|
from pathlib import Path
|
2021-07-30 07:41:02 +02:00
|
|
|
import sys
|
|
|
|
|
|
|
|
import click
|
|
|
|
|
2022-05-22 18:31:35 +02:00
|
|
|
from ordigi import log, LOG
|
2021-08-27 12:45:25 +02:00
|
|
|
from ordigi.collection import Collection
|
2022-07-23 20:12:03 +02:00
|
|
|
from ordigi import constants
|
2021-08-24 17:23:51 +02:00
|
|
|
from ordigi.geolocation import GeoLocation
|
2021-12-05 18:27:04 +01:00
|
|
|
from ordigi import utils
|
2021-07-30 07:41:02 +02:00
|
|
|
|
2021-09-18 22:06:34 +02:00
|
|
|
_logger_options = [
|
2022-08-28 13:46:26 +02:00
|
|
|
click.option(
|
|
|
|
'--quiet',
|
|
|
|
'-q',
|
|
|
|
default=False,
|
|
|
|
is_flag=True,
|
|
|
|
help='Log level set to ERROR',
|
|
|
|
),
|
2021-10-15 19:56:50 +02:00
|
|
|
click.option(
|
|
|
|
'--verbose',
|
|
|
|
'-v',
|
2022-08-28 13:46:26 +02:00
|
|
|
default=False,
|
|
|
|
is_flag=True,
|
|
|
|
help='Log level set to INFO',
|
|
|
|
),
|
|
|
|
click.option(
|
|
|
|
'--debug',
|
|
|
|
'-d',
|
|
|
|
default=False,
|
|
|
|
is_flag=True,
|
|
|
|
help='Log level set to DEBUG',
|
2021-10-15 19:56:50 +02:00
|
|
|
),
|
2021-09-18 22:06:34 +02:00
|
|
|
]
|
|
|
|
|
2021-10-27 00:06:38 +02:00
|
|
|
_input_options = [
|
|
|
|
click.option(
|
|
|
|
'--interactive', '-i', default=False, is_flag=True, help="Interactive mode"
|
|
|
|
),
|
|
|
|
]
|
|
|
|
|
2021-09-18 22:06:34 +02:00
|
|
|
_dry_run_options = [
|
2021-10-15 19:56:50 +02:00
|
|
|
click.option(
|
|
|
|
'--dry-run',
|
|
|
|
default=False,
|
|
|
|
is_flag=True,
|
|
|
|
help='Dry run only, no change made to the filesystem.',
|
2022-04-17 10:18:32 +02:00
|
|
|
),
|
2021-09-18 22:06:34 +02:00
|
|
|
]
|
|
|
|
|
2022-04-17 10:18:32 +02:00
|
|
|
_exclude_options = [
|
2021-10-15 19:56:50 +02:00
|
|
|
click.option(
|
|
|
|
'--exclude',
|
2021-11-06 16:35:35 +01:00
|
|
|
'-E',
|
2021-11-06 17:07:38 +01:00
|
|
|
default=None,
|
2021-10-15 19:56:50 +02:00
|
|
|
multiple=True,
|
|
|
|
help='Directories or files to exclude.',
|
|
|
|
),
|
2022-04-17 10:18:32 +02:00
|
|
|
]
|
|
|
|
|
|
|
|
_filter_options = [
|
2021-10-15 19:56:50 +02:00
|
|
|
click.option(
|
2021-11-06 16:35:35 +01:00
|
|
|
'--ext',
|
|
|
|
'-e',
|
2021-11-06 17:07:38 +01:00
|
|
|
default=None,
|
2021-10-15 19:56:50 +02:00
|
|
|
multiple=True,
|
|
|
|
help="""Use filename
|
2021-09-18 22:06:34 +02:00
|
|
|
extension to filter files for sorting. If value is '*', use
|
|
|
|
common media file extension for filtering. Ignored files remain in
|
2021-10-15 19:56:50 +02:00
|
|
|
the same directory structure""",
|
|
|
|
),
|
2021-11-03 21:29:06 +01:00
|
|
|
click.option(
|
|
|
|
'--ignore-tags',
|
|
|
|
'-I',
|
2021-11-06 17:07:38 +01:00
|
|
|
default=None,
|
2021-11-03 21:29:06 +01:00
|
|
|
multiple=True,
|
|
|
|
help='Specific tags or group that will be ignored when\
|
|
|
|
searching for file data. Example \'File:FileModifyDate\' or \'Filename\'',
|
|
|
|
),
|
2021-10-15 19:56:50 +02:00
|
|
|
click.option('--glob', '-g', default='**/*', help='Glob file selection'),
|
2021-09-18 22:06:34 +02:00
|
|
|
]
|
|
|
|
|
2021-11-13 10:03:53 +01:00
|
|
|
|
2021-10-27 00:06:38 +02:00
|
|
|
_sort_options = [
|
|
|
|
click.option(
|
|
|
|
'--album-from-folder',
|
2022-04-23 18:39:13 +02:00
|
|
|
'-a',
|
2021-10-27 00:06:38 +02:00
|
|
|
default=False,
|
|
|
|
is_flag=True,
|
|
|
|
help="Use images' folders as their album names.",
|
|
|
|
),
|
2022-04-23 18:39:13 +02:00
|
|
|
click.option(
|
|
|
|
'--fill-date-original',
|
|
|
|
'-O',
|
|
|
|
default=False,
|
|
|
|
is_flag=True,
|
|
|
|
help="Fill date original from date media if not set",
|
|
|
|
),
|
2021-10-27 00:06:38 +02:00
|
|
|
click.option(
|
|
|
|
'--path-format',
|
|
|
|
'-p',
|
2022-07-23 20:12:03 +02:00
|
|
|
default=constants.DEFAULT_PATH_FORMAT,
|
2021-10-27 00:06:38 +02:00
|
|
|
help='Custom featured path format',
|
|
|
|
),
|
|
|
|
click.option(
|
|
|
|
'--remove-duplicates',
|
|
|
|
'-R',
|
|
|
|
default=False,
|
|
|
|
is_flag=True,
|
|
|
|
help='True to remove files that are exactly the same in name\
|
|
|
|
and a file hash',
|
|
|
|
),
|
|
|
|
click.option(
|
|
|
|
'--use-date-filename',
|
|
|
|
'-f',
|
|
|
|
default=False,
|
|
|
|
is_flag=True,
|
|
|
|
help="Use filename date for media original date.",
|
|
|
|
),
|
|
|
|
click.option(
|
2021-12-05 13:39:02 +01:00
|
|
|
'--use-file-dates',
|
2021-10-27 00:06:38 +02:00
|
|
|
'-F',
|
|
|
|
default=False,
|
|
|
|
is_flag=True,
|
|
|
|
help="Use file date created or modified for media original date.",
|
|
|
|
),
|
|
|
|
]
|
2021-09-18 22:06:34 +02:00
|
|
|
|
2021-12-05 13:39:02 +01:00
|
|
|
|
2021-07-30 07:41:02 +02:00
|
|
|
def print_help(command):
|
2021-10-31 15:09:40 +01:00
|
|
|
click.echo(command.get_help(click.Context(command)))
|
2021-07-30 07:41:02 +02:00
|
|
|
|
|
|
|
|
2021-09-18 22:06:34 +02:00
|
|
|
def add_options(options):
|
|
|
|
def _add_options(func):
|
|
|
|
for option in reversed(options):
|
|
|
|
func = option(func)
|
|
|
|
return func
|
2021-10-15 19:56:50 +02:00
|
|
|
|
2021-09-18 22:06:34 +02:00
|
|
|
return _add_options
|
|
|
|
|
|
|
|
|
2021-10-27 00:06:38 +02:00
|
|
|
def _get_paths(paths, root):
|
2021-11-03 21:29:06 +01:00
|
|
|
root = Path(root).expanduser().absolute()
|
2021-10-27 00:06:38 +02:00
|
|
|
if not paths:
|
2022-04-17 21:47:08 +02:00
|
|
|
absolute_paths = {root}
|
2021-10-31 15:09:40 +01:00
|
|
|
else:
|
2022-04-17 21:47:08 +02:00
|
|
|
absolute_paths = set()
|
2021-10-31 18:01:19 +01:00
|
|
|
for path in paths:
|
2022-04-17 21:47:08 +02:00
|
|
|
absolute_paths.add(Path(path).expanduser().absolute())
|
2021-10-31 15:09:40 +01:00
|
|
|
|
2022-04-17 21:47:08 +02:00
|
|
|
return absolute_paths, root
|
2021-10-31 15:09:40 +01:00
|
|
|
|
2021-10-27 00:06:38 +02:00
|
|
|
|
2021-12-05 13:39:02 +01:00
|
|
|
def _cli_get_location(collection):
|
|
|
|
gopt = collection.opt['Geolocation']
|
|
|
|
return GeoLocation(
|
2022-04-21 07:09:28 +02:00
|
|
|
gopt['geocoder'],
|
|
|
|
gopt['prefer_english_names'],
|
|
|
|
gopt['timeout'],
|
2021-12-05 13:39:02 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2022-07-23 20:12:03 +02:00
|
|
|
def _cli_sort(collection, src_paths, import_mode):
|
2021-12-05 13:39:02 +01:00
|
|
|
loc = _cli_get_location(collection)
|
|
|
|
|
2022-07-23 20:12:03 +02:00
|
|
|
return collection.sort_files(src_paths, loc, import_mode)
|
2021-12-05 13:39:02 +01:00
|
|
|
|
|
|
|
|
|
|
|
@click.group()
|
|
|
|
def cli(**kwargs):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
@cli.command('check')
|
2021-09-18 22:06:34 +02:00
|
|
|
@add_options(_logger_options)
|
2021-11-13 10:03:53 +01:00
|
|
|
@click.argument('path', required=True, nargs=1, type=click.Path())
|
|
|
|
def _check(**kwargs):
|
2021-10-27 00:06:38 +02:00
|
|
|
"""
|
2021-11-13 10:03:53 +01:00
|
|
|
Check media collection.
|
2021-07-30 07:41:02 +02:00
|
|
|
"""
|
2021-11-13 10:03:53 +01:00
|
|
|
root = Path(kwargs['path']).expanduser().absolute()
|
|
|
|
|
2022-08-28 13:46:26 +02:00
|
|
|
log_level = log.get_level(kwargs['quiet'], kwargs['verbose'], kwargs['debug'])
|
2021-11-12 20:15:53 +01:00
|
|
|
log.console(LOG, level=log_level)
|
2021-07-30 07:41:02 +02:00
|
|
|
|
2021-11-13 10:03:53 +01:00
|
|
|
collection = Collection(root)
|
|
|
|
result = collection.check_db()
|
|
|
|
if result:
|
|
|
|
summary = collection.check_files()
|
|
|
|
if log_level < 30:
|
|
|
|
summary.print()
|
|
|
|
if summary.errors:
|
2022-07-27 03:28:24 +02:00
|
|
|
LOG.error('Db data is not accurate run `ordigi update --checksum`')
|
2021-11-13 10:03:53 +01:00
|
|
|
sys.exit(1)
|
|
|
|
else:
|
2021-12-05 18:27:04 +01:00
|
|
|
LOG.error('Db data is not accurate run `ordigi update`')
|
2021-07-30 07:41:02 +02:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
2021-12-05 13:39:02 +01:00
|
|
|
@cli.command('clean')
|
2021-09-18 22:06:34 +02:00
|
|
|
@add_options(_logger_options)
|
|
|
|
@add_options(_dry_run_options)
|
2021-10-27 00:06:38 +02:00
|
|
|
@add_options(_filter_options)
|
2021-10-15 19:56:50 +02:00
|
|
|
@click.option(
|
|
|
|
'--dedup-regex',
|
2022-08-28 13:46:26 +02:00
|
|
|
'-D',
|
2021-11-06 17:07:38 +01:00
|
|
|
default=None,
|
2021-10-15 19:56:50 +02:00
|
|
|
multiple=True,
|
|
|
|
help='Regex to match duplicate strings parts',
|
|
|
|
)
|
|
|
|
@click.option(
|
2021-10-17 17:55:13 +02:00
|
|
|
'--delete-excluded', '-d', default=False, is_flag=True, help='Remove excluded files'
|
2021-10-15 19:56:50 +02:00
|
|
|
)
|
|
|
|
@click.option(
|
2021-10-17 17:55:13 +02:00
|
|
|
'--folders', '-f', default=False, is_flag=True, help='Remove empty folders'
|
2021-10-15 19:56:50 +02:00
|
|
|
)
|
|
|
|
@click.option(
|
|
|
|
'--path-string', '-p', default=False, is_flag=True, help='Deduplicate path string'
|
|
|
|
)
|
|
|
|
@click.option(
|
|
|
|
'--remove-duplicates',
|
|
|
|
'-R',
|
|
|
|
default=False,
|
|
|
|
is_flag=True,
|
|
|
|
help='True to remove files that are exactly the same in name and a file hash',
|
|
|
|
)
|
2021-10-27 00:06:38 +02:00
|
|
|
@click.argument('subdirs', required=False, nargs=-1, type=click.Path())
|
2021-10-31 15:09:40 +01:00
|
|
|
@click.argument('collection', required=True, nargs=1, type=click.Path())
|
2021-10-27 00:06:38 +02:00
|
|
|
def _clean(**kwargs):
|
2022-07-23 20:15:34 +02:00
|
|
|
"""Clean media collection"""
|
2021-08-14 21:37:43 +02:00
|
|
|
|
2021-09-18 22:06:34 +02:00
|
|
|
folders = kwargs['folders']
|
2022-08-28 13:46:26 +02:00
|
|
|
log_level = log.get_level(kwargs['quiet'], kwargs['verbose'], kwargs['debug'])
|
2021-11-12 20:15:53 +01:00
|
|
|
log.console(LOG, level=log_level)
|
2021-09-18 22:06:34 +02:00
|
|
|
|
2021-10-27 00:06:38 +02:00
|
|
|
subdirs = kwargs['subdirs']
|
2021-10-31 15:09:40 +01:00
|
|
|
root = kwargs['collection']
|
2021-10-31 18:01:19 +01:00
|
|
|
paths, root = _get_paths(subdirs, root)
|
2021-08-14 21:37:43 +02:00
|
|
|
|
2021-10-16 19:29:52 +02:00
|
|
|
collection = Collection(
|
|
|
|
root,
|
2021-11-19 18:24:35 +01:00
|
|
|
{
|
2022-07-23 20:12:03 +02:00
|
|
|
'dry_run': kwargs['dry_run'],
|
|
|
|
'extensions': kwargs['ext'],
|
|
|
|
'glob': kwargs['glob'],
|
|
|
|
'remove_duplicates': kwargs['remove_duplicates'],
|
2021-11-19 18:24:35 +01:00
|
|
|
},
|
2021-10-16 19:29:52 +02:00
|
|
|
)
|
|
|
|
|
2021-12-05 13:39:02 +01:00
|
|
|
# os.path.join(
|
|
|
|
# TODO make function to remove duplicates
|
|
|
|
# path_format = collection.opt['Path']['path_format']
|
2022-07-23 20:12:03 +02:00
|
|
|
# summary = collection.sort_files(paths, None)
|
2021-11-13 10:03:53 +01:00
|
|
|
|
2021-10-31 15:09:40 +01:00
|
|
|
if kwargs['path_string']:
|
|
|
|
dedup_regex = set(kwargs['dedup_regex'])
|
2022-07-23 20:12:03 +02:00
|
|
|
collection.dedup_path(paths, dedup_regex)
|
2021-10-27 00:06:38 +02:00
|
|
|
|
2021-10-31 15:09:40 +01:00
|
|
|
for path in paths:
|
2021-11-13 10:03:53 +01:00
|
|
|
if folders:
|
2021-10-27 00:06:38 +02:00
|
|
|
collection.remove_empty_folders(path)
|
2021-08-31 16:18:41 +02:00
|
|
|
|
2021-10-27 00:06:38 +02:00
|
|
|
if kwargs['delete_excluded']:
|
|
|
|
collection.remove_excluded_files()
|
2021-08-27 12:45:25 +02:00
|
|
|
|
2021-10-27 00:06:38 +02:00
|
|
|
summary = collection.summary
|
2021-10-17 17:55:13 +02:00
|
|
|
|
2021-10-16 19:29:52 +02:00
|
|
|
if log_level < 30:
|
2021-09-29 07:36:47 +02:00
|
|
|
summary.print()
|
2021-08-27 12:45:25 +02:00
|
|
|
|
2021-10-27 00:06:38 +02:00
|
|
|
if summary.errors:
|
2021-08-27 12:45:25 +02:00
|
|
|
sys.exit(1)
|
2021-08-14 21:37:43 +02:00
|
|
|
|
|
|
|
|
2021-12-05 18:27:04 +01:00
|
|
|
@cli.command('clone')
|
|
|
|
@add_options(_logger_options)
|
|
|
|
@add_options(_dry_run_options)
|
|
|
|
@click.argument('src', required=True, nargs=1, type=click.Path())
|
|
|
|
@click.argument('dest', required=True, nargs=1, type=click.Path())
|
|
|
|
def _clone(**kwargs):
|
|
|
|
"""Clone media collection to another location"""
|
|
|
|
|
2022-08-28 13:46:26 +02:00
|
|
|
log_level = log.get_level(kwargs['quiet'], kwargs['verbose'], kwargs['debug'])
|
2021-12-05 18:27:04 +01:00
|
|
|
log.console(LOG, level=log_level)
|
|
|
|
|
|
|
|
src_path = Path(kwargs['src']).expanduser().absolute()
|
|
|
|
dest_path = Path(kwargs['dest']).expanduser().absolute()
|
|
|
|
|
|
|
|
dry_run = kwargs['dry_run']
|
|
|
|
|
|
|
|
src_collection = Collection(
|
|
|
|
src_path, {'cache': True, 'dry_run': dry_run}
|
|
|
|
)
|
|
|
|
|
|
|
|
if dest_path.exists() and not utils.empty_dir(dest_path):
|
|
|
|
LOG.error(f'Destination collection path {dest_path} must be empty directory')
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
summary = src_collection.clone(dest_path)
|
|
|
|
|
|
|
|
if log_level < 30:
|
|
|
|
summary.print()
|
|
|
|
|
|
|
|
if summary.errors:
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
2021-12-05 13:39:02 +01:00
|
|
|
@cli.command('compare')
|
2021-09-18 22:06:34 +02:00
|
|
|
@add_options(_logger_options)
|
2021-11-13 10:03:53 +01:00
|
|
|
@add_options(_dry_run_options)
|
|
|
|
@add_options(_filter_options)
|
|
|
|
@click.option('--find-duplicates', '-f', default=False, is_flag=True)
|
|
|
|
@click.option('--remove-duplicates', '-r', default=False, is_flag=True)
|
|
|
|
@click.option(
|
|
|
|
'--similar-to',
|
|
|
|
'-s',
|
|
|
|
default=False,
|
|
|
|
help='Similar to given image',
|
|
|
|
)
|
|
|
|
@click.option(
|
|
|
|
'--similarity',
|
|
|
|
'-S',
|
|
|
|
default=80,
|
|
|
|
help='Similarity level for images',
|
|
|
|
)
|
|
|
|
@click.argument('subdirs', required=False, nargs=-1, type=click.Path())
|
|
|
|
@click.argument('collection', required=True, nargs=1, type=click.Path())
|
|
|
|
def _compare(**kwargs):
|
2021-10-27 00:06:38 +02:00
|
|
|
"""
|
2021-11-13 10:03:53 +01:00
|
|
|
Sort similar images in directories
|
2021-10-27 00:06:38 +02:00
|
|
|
"""
|
2021-11-13 10:03:53 +01:00
|
|
|
|
|
|
|
subdirs = kwargs['subdirs']
|
|
|
|
root = kwargs['collection']
|
|
|
|
|
2022-08-28 13:46:26 +02:00
|
|
|
log_level = log.get_level(kwargs['quiet'], kwargs['verbose'], kwargs['debug'])
|
2021-11-12 20:15:53 +01:00
|
|
|
log.console(LOG, level=log_level)
|
2021-11-13 10:03:53 +01:00
|
|
|
paths, root = _get_paths(subdirs, root)
|
2021-10-16 19:29:52 +02:00
|
|
|
|
2021-11-13 10:03:53 +01:00
|
|
|
collection = Collection(
|
|
|
|
root,
|
2021-11-19 18:24:35 +01:00
|
|
|
{
|
2022-07-23 20:12:03 +02:00
|
|
|
'extensions': kwargs['ext'],
|
|
|
|
'glob': kwargs['glob'],
|
|
|
|
'dry_run': kwargs['dry_run'],
|
|
|
|
'remove_duplicates': kwargs['remove_duplicates'],
|
2021-11-19 18:24:35 +01:00
|
|
|
},
|
2021-11-13 10:03:53 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
for path in paths:
|
|
|
|
collection.sort_similar_images(path, kwargs['similarity'])
|
|
|
|
|
|
|
|
summary = collection.summary
|
2021-10-16 19:29:52 +02:00
|
|
|
|
|
|
|
if log_level < 30:
|
2021-10-15 06:41:22 +02:00
|
|
|
summary.print()
|
2021-07-30 07:41:02 +02:00
|
|
|
|
2021-11-13 10:03:53 +01:00
|
|
|
if summary.errors:
|
|
|
|
sys.exit(1)
|
|
|
|
|
2021-07-30 07:41:02 +02:00
|
|
|
|
2022-04-17 22:05:13 +02:00
|
|
|
@cli.command('edit')
|
|
|
|
@add_options(_logger_options)
|
2022-04-18 19:38:41 +02:00
|
|
|
@add_options(_exclude_options)
|
2022-04-17 22:05:13 +02:00
|
|
|
@add_options(_filter_options)
|
|
|
|
@click.option(
|
|
|
|
'--key',
|
|
|
|
'-k',
|
|
|
|
default=None,
|
|
|
|
multiple=True,
|
|
|
|
help="Select exif tags groups to edit",
|
|
|
|
)
|
2022-07-27 03:16:25 +02:00
|
|
|
@click.option(
|
|
|
|
'--overwrite',
|
|
|
|
'-O',
|
|
|
|
default=False,
|
|
|
|
is_flag=True,
|
|
|
|
help="Overwrite db and exif value by key value",
|
|
|
|
)
|
2022-04-17 22:05:13 +02:00
|
|
|
@click.argument('subdirs', required=False, nargs=-1, type=click.Path())
|
|
|
|
@click.argument('path', required=True, nargs=1, type=click.Path())
|
|
|
|
def _edit(**kwargs):
|
|
|
|
"""Edit EXIF metadata in files or directories"""
|
|
|
|
|
2022-08-28 13:46:26 +02:00
|
|
|
log_level = log.get_level(kwargs['quiet'], kwargs['verbose'], kwargs['debug'])
|
2022-04-17 22:05:13 +02:00
|
|
|
log.console(LOG, level=log_level)
|
|
|
|
|
|
|
|
paths, root = _get_paths(kwargs['subdirs'], kwargs['path'])
|
|
|
|
|
2022-07-27 03:16:25 +02:00
|
|
|
overwrite = kwargs['overwrite']
|
|
|
|
|
2022-04-17 22:05:13 +02:00
|
|
|
collection = Collection(
|
|
|
|
root,
|
|
|
|
{
|
|
|
|
'cache': True,
|
|
|
|
'ignore_tags': kwargs['ignore_tags'],
|
|
|
|
'exclude': kwargs['exclude'],
|
|
|
|
'extensions': kwargs['ext'],
|
|
|
|
'glob': kwargs['glob'],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2022-04-23 13:01:55 +02:00
|
|
|
editable_keys = (
|
|
|
|
'album',
|
|
|
|
'camera_make',
|
|
|
|
'camera_model',
|
|
|
|
'city',
|
|
|
|
'country',
|
|
|
|
# 'date_created',
|
|
|
|
'date_media',
|
|
|
|
# 'date_modified',
|
|
|
|
'date_original',
|
|
|
|
'latitude',
|
|
|
|
'location',
|
|
|
|
'longitude',
|
|
|
|
'latitude_ref',
|
|
|
|
'longitude_ref',
|
|
|
|
'original_name',
|
|
|
|
'state',
|
|
|
|
'title',
|
|
|
|
)
|
|
|
|
|
|
|
|
if not kwargs['key']:
|
|
|
|
keys = set(editable_keys)
|
|
|
|
else:
|
|
|
|
keys = set(kwargs['key'])
|
2022-07-27 03:16:25 +02:00
|
|
|
if 'coordinates' in keys:
|
|
|
|
keys.remove('coordinates')
|
|
|
|
keys.update(['latitude', 'longitude'])
|
2022-04-23 13:01:55 +02:00
|
|
|
|
2022-04-17 22:05:13 +02:00
|
|
|
location = False
|
2022-04-23 13:01:55 +02:00
|
|
|
for key in keys:
|
|
|
|
if key not in editable_keys:
|
2022-04-17 22:05:13 +02:00
|
|
|
LOG.error(f"key '{key}' is not valid")
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
if key in (
|
2022-04-23 13:01:55 +02:00
|
|
|
'city',
|
2022-04-17 22:05:13 +02:00
|
|
|
'latitude',
|
2022-04-23 13:01:55 +02:00
|
|
|
'location',
|
2022-04-17 22:05:13 +02:00
|
|
|
'longitude',
|
|
|
|
'latitude_ref',
|
|
|
|
'longitude_ref',
|
|
|
|
):
|
|
|
|
location = True
|
|
|
|
|
|
|
|
if location:
|
|
|
|
loc = _cli_get_location(collection)
|
|
|
|
else:
|
|
|
|
loc = None
|
|
|
|
|
2022-07-27 03:16:25 +02:00
|
|
|
summary = collection.edit_metadata(paths, keys, loc, overwrite)
|
2022-04-17 22:05:13 +02:00
|
|
|
|
|
|
|
if log_level < 30:
|
|
|
|
summary.print()
|
|
|
|
|
|
|
|
if summary.errors:
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
2021-12-05 13:39:02 +01:00
|
|
|
@cli.command('init')
|
2021-09-18 22:06:34 +02:00
|
|
|
@add_options(_logger_options)
|
2021-10-15 06:41:22 +02:00
|
|
|
@click.argument('path', required=True, nargs=1, type=click.Path())
|
2021-11-13 10:03:53 +01:00
|
|
|
def _init(**kwargs):
|
2021-10-27 00:06:38 +02:00
|
|
|
"""
|
2021-11-13 10:03:53 +01:00
|
|
|
Init media collection database.
|
2021-10-27 00:06:38 +02:00
|
|
|
"""
|
2021-11-03 21:29:06 +01:00
|
|
|
root = Path(kwargs['path']).expanduser().absolute()
|
2022-08-28 13:46:26 +02:00
|
|
|
log_level = log.get_level(kwargs['quiet'], kwargs['verbose'], kwargs['debug'])
|
2021-11-12 20:15:53 +01:00
|
|
|
log.console(LOG, level=log_level)
|
2021-10-16 19:29:52 +02:00
|
|
|
|
2021-11-13 10:03:53 +01:00
|
|
|
collection = Collection(root)
|
|
|
|
|
2021-12-05 13:39:02 +01:00
|
|
|
loc = _cli_get_location(collection)
|
2021-11-13 10:03:53 +01:00
|
|
|
|
|
|
|
summary = collection.init(loc)
|
2021-10-16 19:29:52 +02:00
|
|
|
|
|
|
|
if log_level < 30:
|
2021-10-15 06:41:22 +02:00
|
|
|
summary.print()
|
|
|
|
|
2022-04-17 22:05:13 +02:00
|
|
|
if summary.errors:
|
|
|
|
sys.exit(1)
|
|
|
|
|
2021-10-15 06:41:22 +02:00
|
|
|
|
2021-12-05 13:39:02 +01:00
|
|
|
@cli.command('import')
|
2021-10-15 06:41:22 +02:00
|
|
|
@add_options(_logger_options)
|
2021-11-13 10:03:53 +01:00
|
|
|
@add_options(_input_options)
|
|
|
|
@add_options(_dry_run_options)
|
2022-04-17 10:18:32 +02:00
|
|
|
@add_options(_exclude_options)
|
2021-11-13 10:03:53 +01:00
|
|
|
@add_options(_filter_options)
|
|
|
|
@add_options(_sort_options)
|
|
|
|
@click.option(
|
|
|
|
'--copy',
|
|
|
|
'-c',
|
|
|
|
default=False,
|
|
|
|
is_flag=True,
|
|
|
|
help='True if you want files to be copied over from src_dir to\
|
|
|
|
dest_dir rather than moved',
|
|
|
|
)
|
|
|
|
@click.argument('src', required=False, nargs=-1, type=click.Path())
|
|
|
|
@click.argument('dest', required=True, nargs=1, type=click.Path())
|
|
|
|
def _import(**kwargs):
|
|
|
|
"""Sort files or directories by reading their EXIF and organizing them
|
|
|
|
according to ordigi.conf preferences.
|
2021-10-27 00:06:38 +02:00
|
|
|
"""
|
2022-08-28 13:46:26 +02:00
|
|
|
log_level = log.get_level(kwargs['quiet'], kwargs['verbose'], kwargs['debug'])
|
2021-11-12 20:15:53 +01:00
|
|
|
log.console(LOG, level=log_level)
|
2021-11-13 10:03:53 +01:00
|
|
|
|
|
|
|
src_paths, root = _get_paths(kwargs['src'], kwargs['dest'])
|
|
|
|
|
|
|
|
collection = Collection(
|
|
|
|
root,
|
2021-11-19 18:24:35 +01:00
|
|
|
{
|
|
|
|
'album_from_folder': kwargs['album_from_folder'],
|
|
|
|
'cache': False,
|
|
|
|
'ignore_tags': kwargs['ignore_tags'],
|
|
|
|
'use_date_filename': kwargs['use_date_filename'],
|
|
|
|
'use_file_dates': kwargs['use_file_dates'],
|
|
|
|
'exclude': kwargs['exclude'],
|
|
|
|
'extensions': kwargs['ext'],
|
|
|
|
'glob': kwargs['glob'],
|
|
|
|
'dry_run': kwargs['dry_run'],
|
|
|
|
'interactive': kwargs['interactive'],
|
2021-12-05 13:39:02 +01:00
|
|
|
'path_format': kwargs['path_format'],
|
2022-07-23 20:12:03 +02:00
|
|
|
'remove_duplicates': kwargs['remove_duplicates'],
|
2021-11-19 18:24:35 +01:00
|
|
|
}
|
2021-11-13 10:03:53 +01:00
|
|
|
)
|
2021-07-30 07:41:02 +02:00
|
|
|
|
2021-12-05 13:39:02 +01:00
|
|
|
if kwargs['copy']:
|
|
|
|
import_mode = 'copy'
|
|
|
|
else:
|
|
|
|
import_mode = 'move'
|
2022-07-23 20:12:03 +02:00
|
|
|
summary = _cli_sort(collection, src_paths, import_mode)
|
2021-11-13 10:03:53 +01:00
|
|
|
|
|
|
|
if log_level < 30:
|
|
|
|
summary.print()
|
|
|
|
|
|
|
|
if summary.errors:
|
|
|
|
sys.exit(1)
|
|
|
|
|
2021-12-05 13:39:02 +01:00
|
|
|
|
|
|
|
@cli.command('sort')
|
2021-09-18 22:06:34 +02:00
|
|
|
@add_options(_logger_options)
|
2021-11-13 10:03:53 +01:00
|
|
|
@add_options(_input_options)
|
2021-09-18 22:06:34 +02:00
|
|
|
@add_options(_dry_run_options)
|
2021-10-27 00:06:38 +02:00
|
|
|
@add_options(_filter_options)
|
2021-11-13 10:03:53 +01:00
|
|
|
@add_options(_sort_options)
|
|
|
|
@click.option('--clean', '-C', default=False, is_flag=True, help='Clean empty folders')
|
2021-10-15 19:56:50 +02:00
|
|
|
@click.option(
|
2021-11-13 10:03:53 +01:00
|
|
|
'--reset-cache',
|
|
|
|
'-r',
|
2021-10-15 19:56:50 +02:00
|
|
|
default=False,
|
2021-11-13 10:03:53 +01:00
|
|
|
is_flag=True,
|
|
|
|
help='Regenerate the hash.json and location.json database ',
|
2021-10-15 19:56:50 +02:00
|
|
|
)
|
2021-10-27 00:06:38 +02:00
|
|
|
@click.argument('subdirs', required=False, nargs=-1, type=click.Path())
|
2021-11-13 10:03:53 +01:00
|
|
|
@click.argument('dest', required=True, nargs=1, type=click.Path())
|
|
|
|
def _sort(**kwargs):
|
|
|
|
"""Sort files or directories by reading their EXIF and organizing them
|
|
|
|
according to ordigi.conf preferences.
|
2021-10-27 00:06:38 +02:00
|
|
|
"""
|
2022-08-28 13:46:26 +02:00
|
|
|
log_level = log.get_level(kwargs['quiet'], kwargs['verbose'], kwargs['debug'])
|
2021-11-12 20:15:53 +01:00
|
|
|
log.console(LOG, level=log_level)
|
2021-07-30 07:41:02 +02:00
|
|
|
|
2021-11-13 10:03:53 +01:00
|
|
|
paths, root = _get_paths(kwargs['subdirs'], kwargs['dest'])
|
2021-08-27 12:45:25 +02:00
|
|
|
|
2021-11-13 10:03:53 +01:00
|
|
|
cache = not kwargs['reset_cache']
|
2021-09-18 22:06:34 +02:00
|
|
|
|
2021-10-15 19:56:50 +02:00
|
|
|
collection = Collection(
|
|
|
|
root,
|
2021-11-19 18:24:35 +01:00
|
|
|
{
|
|
|
|
'album_from_folder': kwargs['album_from_folder'],
|
|
|
|
'cache': cache,
|
2022-04-23 18:39:13 +02:00
|
|
|
'fill_date_original': kwargs['fill_date_original'],
|
2021-11-19 18:24:35 +01:00
|
|
|
'ignore_tags': kwargs['ignore_tags'],
|
|
|
|
'use_date_filename': kwargs['use_date_filename'],
|
|
|
|
'use_file_dates': kwargs['use_file_dates'],
|
|
|
|
'extensions': kwargs['ext'],
|
|
|
|
'glob': kwargs['glob'],
|
|
|
|
'dry_run': kwargs['dry_run'],
|
|
|
|
'interactive': kwargs['interactive'],
|
2022-07-23 20:12:03 +02:00
|
|
|
'remove_duplicates': kwargs['remove_duplicates'],
|
2021-11-19 18:24:35 +01:00
|
|
|
}
|
2021-10-15 19:56:50 +02:00
|
|
|
)
|
2021-07-30 07:41:02 +02:00
|
|
|
|
2022-07-23 20:12:03 +02:00
|
|
|
summary = _cli_sort(collection, paths, False)
|
2021-11-13 10:03:53 +01:00
|
|
|
|
|
|
|
if kwargs['clean']:
|
|
|
|
collection.remove_empty_folders(root)
|
2021-07-30 07:41:02 +02:00
|
|
|
|
2021-10-16 19:29:52 +02:00
|
|
|
if log_level < 30:
|
2021-09-29 07:36:47 +02:00
|
|
|
summary.print()
|
2021-07-30 07:41:02 +02:00
|
|
|
|
2021-10-27 00:06:38 +02:00
|
|
|
if summary.errors:
|
2021-07-30 07:41:02 +02:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
2021-12-05 13:39:02 +01:00
|
|
|
@cli.command('update')
|
2021-11-13 10:03:53 +01:00
|
|
|
@add_options(_logger_options)
|
2022-07-27 03:28:24 +02:00
|
|
|
@click.option(
|
|
|
|
'--checksum',
|
|
|
|
'-c',
|
|
|
|
default=False,
|
|
|
|
is_flag=True,
|
|
|
|
help='Update checksum, assuming file are changed by the user',
|
|
|
|
)
|
2021-11-13 10:03:53 +01:00
|
|
|
@click.argument('path', required=True, nargs=1, type=click.Path())
|
|
|
|
def _update(**kwargs):
|
|
|
|
"""
|
|
|
|
Update media collection database.
|
|
|
|
"""
|
|
|
|
root = Path(kwargs['path']).expanduser().absolute()
|
2022-08-28 13:46:26 +02:00
|
|
|
log_level = log.get_level(kwargs['quiet'], kwargs['verbose'], kwargs['debug'])
|
2021-11-13 10:03:53 +01:00
|
|
|
log.console(LOG, level=log_level)
|
|
|
|
|
|
|
|
collection = Collection(root)
|
2021-12-05 13:39:02 +01:00
|
|
|
loc = _cli_get_location(collection)
|
2022-07-27 03:28:24 +02:00
|
|
|
summary = collection.update(loc, kwargs['checksum'])
|
2021-11-13 10:03:53 +01:00
|
|
|
|
|
|
|
if log_level < 30:
|
|
|
|
summary.print()
|
|
|
|
|
|
|
|
|
2021-12-05 13:39:02 +01:00
|
|
|
if __name__ == '__main__':
|
|
|
|
cli()
|