Fix edit metadata
This commit is contained in:
parent
5f0237a48f
commit
a4746cbf60
|
@ -346,6 +346,87 @@ def _compare(**kwargs):
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
@cli.command('edit')
|
||||||
|
@add_options(_logger_options)
|
||||||
|
@add_options(_filter_options)
|
||||||
|
@click.option(
|
||||||
|
'--key',
|
||||||
|
'-k',
|
||||||
|
default=None,
|
||||||
|
multiple=True,
|
||||||
|
# TODO Allow edit all values
|
||||||
|
required=True,
|
||||||
|
help="Select exif tags groups to edit",
|
||||||
|
)
|
||||||
|
@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"""
|
||||||
|
|
||||||
|
log_level = log.get_level(kwargs['verbose'])
|
||||||
|
log.console(LOG, level=log_level)
|
||||||
|
|
||||||
|
paths, root = _get_paths(kwargs['subdirs'], kwargs['path'])
|
||||||
|
|
||||||
|
collection = Collection(
|
||||||
|
root,
|
||||||
|
{
|
||||||
|
'cache': True,
|
||||||
|
'ignore_tags': kwargs['ignore_tags'],
|
||||||
|
'exclude': kwargs['exclude'],
|
||||||
|
'extensions': kwargs['ext'],
|
||||||
|
'glob': kwargs['glob'],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
location = False
|
||||||
|
keys = set()
|
||||||
|
for key in kwargs['key']:
|
||||||
|
if key not in (
|
||||||
|
'album',
|
||||||
|
'camera_make',
|
||||||
|
'camera_model',
|
||||||
|
'coordinates',
|
||||||
|
'date_original',
|
||||||
|
'date_created',
|
||||||
|
'date_modified',
|
||||||
|
'latitude',
|
||||||
|
'longitude',
|
||||||
|
'latitude_ref',
|
||||||
|
'longitude_ref',
|
||||||
|
'original_name',
|
||||||
|
'title',
|
||||||
|
):
|
||||||
|
LOG.error(f"key '{key}' is not valid")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if key in (
|
||||||
|
'latitude',
|
||||||
|
'longitude',
|
||||||
|
'latitude_ref',
|
||||||
|
'longitude_ref',
|
||||||
|
):
|
||||||
|
location = True
|
||||||
|
|
||||||
|
if key == 'coordinates':
|
||||||
|
keys.update(['latitude', 'longitude'])
|
||||||
|
else:
|
||||||
|
keys.add(key)
|
||||||
|
|
||||||
|
if location:
|
||||||
|
loc = _cli_get_location(collection)
|
||||||
|
else:
|
||||||
|
loc = None
|
||||||
|
|
||||||
|
summary = collection.edit_metadata(paths, keys, loc, overwrite=True)
|
||||||
|
|
||||||
|
if log_level < 30:
|
||||||
|
summary.print()
|
||||||
|
|
||||||
|
if summary.errors:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
@cli.command('init')
|
@cli.command('init')
|
||||||
@add_options(_logger_options)
|
@add_options(_logger_options)
|
||||||
@click.argument('path', required=True, nargs=1, type=click.Path())
|
@click.argument('path', required=True, nargs=1, type=click.Path())
|
||||||
|
@ -366,6 +447,9 @@ def _init(**kwargs):
|
||||||
if log_level < 30:
|
if log_level < 30:
|
||||||
summary.print()
|
summary.print()
|
||||||
|
|
||||||
|
if summary.errors:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
@cli.command('import')
|
@cli.command('import')
|
||||||
@add_options(_logger_options)
|
@add_options(_logger_options)
|
||||||
|
|
|
@ -543,6 +543,7 @@ class SortMedias:
|
||||||
|
|
||||||
def sort_file(self, src_path, dest_path, metadata, imp=False):
|
def sort_file(self, src_path, dest_path, metadata, imp=False):
|
||||||
"""Sort file and register it to db"""
|
"""Sort file and register it to db"""
|
||||||
|
|
||||||
if imp == 'copy':
|
if imp == 'copy':
|
||||||
self.fileio.copy(src_path, dest_path)
|
self.fileio.copy(src_path, dest_path)
|
||||||
else:
|
else:
|
||||||
|
@ -1130,69 +1131,50 @@ class Collection(SortMedias):
|
||||||
|
|
||||||
return self.summary
|
return self.summary
|
||||||
|
|
||||||
def edit_metadata(self, path, key, loc=None, overwrite=False):
|
def edit_metadata(self, paths, keys, loc=None, overwrite=False):
|
||||||
"""Fill metadata and exif data for given key"""
|
"""Edit metadata and exif data for given key"""
|
||||||
self._init_check_db()
|
self._init_check_db()
|
||||||
|
|
||||||
if key in (
|
for file_path, media in self.medias.get_medias_datas(paths, loc=loc):
|
||||||
'latitude',
|
|
||||||
'longitude',
|
|
||||||
'latitude_ref',
|
|
||||||
'longitude_ref',
|
|
||||||
):
|
|
||||||
print(f"Set {key} alone is not allowed")
|
|
||||||
return None
|
|
||||||
|
|
||||||
if overwrite:
|
|
||||||
print(f"Edit {key} values:")
|
|
||||||
else:
|
|
||||||
print(f"Fill empty {key} values:")
|
|
||||||
|
|
||||||
paths = self.paths.get_paths_list(path)
|
|
||||||
|
|
||||||
for file_path in paths:
|
|
||||||
media = self.medias.get_media(file_path, self.root)
|
|
||||||
media.get_metadata(
|
|
||||||
self.root, loc, self.db.sqlite, False
|
|
||||||
)
|
|
||||||
media.metadata['file_path'] = os.path.relpath(file_path, self.root)
|
media.metadata['file_path'] = os.path.relpath(file_path, self.root)
|
||||||
print()
|
for key in keys:
|
||||||
value = media.metadata[key]
|
print()
|
||||||
if overwrite or not value:
|
value = media.metadata[key]
|
||||||
print(f"FILE: '{file_path}'")
|
if overwrite or not value:
|
||||||
if overwrite:
|
print(f"FILE: '{file_path}'")
|
||||||
print(f"{key}: '{value}'")
|
if overwrite:
|
||||||
if overwrite or not value:
|
print(f"{key}: '{value}'")
|
||||||
# Prompt value for given key for file_path
|
if overwrite or not value:
|
||||||
# utils.open_file()
|
# Prompt value for given key for file_path
|
||||||
prompt = [
|
prompt = [
|
||||||
inquirer.Text('value', message=key),
|
inquirer.Text('value', message=key),
|
||||||
]
|
]
|
||||||
answer = inquirer.prompt(prompt, theme=self.theme)
|
answer = inquirer.prompt(prompt, theme=self.theme)
|
||||||
# Validate value
|
# answer = {'value': '03-12-2021 08:12:35'}
|
||||||
if key in ('date_original', 'date_created', 'date_modified'):
|
# Validate value
|
||||||
# Check date format
|
if key in ('date_original', 'date_created', 'date_modified'):
|
||||||
value = media.get_date_format(answer['value'])
|
# Check date format
|
||||||
else:
|
value = media.get_date_format(answer['value'])
|
||||||
if not answer[key].isalnum():
|
else:
|
||||||
print("Invalid entry, use alphanumeric chars")
|
if not answer[key].isalnum():
|
||||||
value = inquirer.prompt(prompt, theme=self.theme)
|
print("Invalid entry, use alphanumeric chars")
|
||||||
|
value = inquirer.prompt(prompt, theme=self.theme)
|
||||||
|
|
||||||
result = False
|
result = False
|
||||||
if value:
|
if value:
|
||||||
media.metadata[key] = value
|
media.metadata[key] = value
|
||||||
# Update database
|
# Update database
|
||||||
self.db.add_file_data(media.metadata)
|
self.db.add_file_data(media.metadata)
|
||||||
# Update exif data
|
# Update exif data
|
||||||
exif = WriteExif(
|
exif = WriteExif(
|
||||||
file_path,
|
file_path,
|
||||||
media.metadata,
|
media.metadata,
|
||||||
ignore_tags=self.opt['Exif']['ignore_tags'],
|
ignore_tags=self.opt['Exif']['ignore_tags'],
|
||||||
)
|
)
|
||||||
result = exif.set_key_values(key, value)
|
result = exif.set_key_values(key, value)
|
||||||
if result:
|
if result:
|
||||||
self.summary.append('update', True, file_path)
|
self.summary.append('update', True, file_path)
|
||||||
else:
|
else:
|
||||||
self.summary.append('update', False, file_path)
|
self.summary.append('update', False, file_path)
|
||||||
|
|
||||||
return self.summary
|
return self.summary
|
||||||
|
|
|
@ -665,16 +665,20 @@ class Medias:
|
||||||
|
|
||||||
return media
|
return media
|
||||||
|
|
||||||
def get_metadata(self, file_path, src_dir, loc=None):
|
def get_media_data(self, file_path, src_dir, loc=None):
|
||||||
media = self.get_media(file_path, src_dir)
|
media = self.get_media(file_path, src_dir)
|
||||||
media.get_metadata(
|
media.get_metadata(
|
||||||
self.root, loc, self.db.sqlite, self.exif_opt['cache']
|
self.root, loc, self.db.sqlite, self.exif_opt['cache']
|
||||||
)
|
)
|
||||||
|
|
||||||
return media.metadata
|
return media
|
||||||
|
|
||||||
def get_metadatas(self, src_dirs, imp=False, loc=None):
|
def get_metadata(self, src_path, src_dir, loc=None):
|
||||||
"""Get medias data"""
|
"""Get metadata"""
|
||||||
|
return self.get_media_data(src_path, src_dir, loc).metadata
|
||||||
|
|
||||||
|
def get_paths(self, src_dirs, imp=False):
|
||||||
|
"""Get paths"""
|
||||||
for src_dir in src_dirs:
|
for src_dir in src_dirs:
|
||||||
src_dir = self.paths.check(src_dir)
|
src_dir = self.paths.check(src_dir)
|
||||||
paths = self.paths.get_paths_list(src_dir)
|
paths = self.paths.get_paths_list(src_dir)
|
||||||
|
@ -687,10 +691,23 @@ class Medias:
|
||||||
collection, use `ordigi import`""")
|
collection, use `ordigi import`""")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Get file metadata
|
yield src_dir, src_path
|
||||||
metadata = self.get_metadata(src_path, src_dir, loc)
|
|
||||||
|
|
||||||
yield src_path, metadata
|
def get_medias_datas(self, src_dirs, imp=False, loc=None):
|
||||||
|
"""Get medias datas"""
|
||||||
|
for src_dir, src_path in self.get_paths(src_dirs, imp=imp):
|
||||||
|
# Get file metadata
|
||||||
|
media = self.get_media_data(src_path, src_dir, loc)
|
||||||
|
|
||||||
|
yield src_path, media
|
||||||
|
|
||||||
|
def get_metadatas(self, src_dirs, imp=False, loc=None):
|
||||||
|
"""Get medias data"""
|
||||||
|
for src_dir, src_path in self.get_paths(src_dirs, imp=imp):
|
||||||
|
# Get file metadata
|
||||||
|
metadata = self.get_metadata(src_path, src_dir, loc)
|
||||||
|
|
||||||
|
yield src_path, metadata
|
||||||
|
|
||||||
def update_exif_data(self, metadata):
|
def update_exif_data(self, metadata):
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import shutil
|
||||||
from click.testing import CliRunner
|
from click.testing import CliRunner
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import pytest
|
import pytest
|
||||||
|
import inquirer
|
||||||
|
|
||||||
from ordigi import cli
|
from ordigi import cli
|
||||||
|
|
||||||
|
@ -62,6 +63,7 @@ class TestOrdigi:
|
||||||
cli._check,
|
cli._check,
|
||||||
cli._clean,
|
cli._clean,
|
||||||
cli._compare,
|
cli._compare,
|
||||||
|
cli._edit,
|
||||||
cli._import,
|
cli._import,
|
||||||
cli._init,
|
cli._init,
|
||||||
cli._sort,
|
cli._sort,
|
||||||
|
@ -76,6 +78,32 @@ class TestOrdigi:
|
||||||
|
|
||||||
self.assert_cli(cli._clone, ['not_exist'], state=2)
|
self.assert_cli(cli._clone, ['not_exist'], state=2)
|
||||||
|
|
||||||
|
def test_edit(self, monkeypatch):
|
||||||
|
|
||||||
|
bool_options = ()
|
||||||
|
|
||||||
|
arg_options = (
|
||||||
|
*self.logger_options,
|
||||||
|
*self.filter_options,
|
||||||
|
)
|
||||||
|
|
||||||
|
def mockreturn(prompt, theme):
|
||||||
|
return {'value': '03-12-2021 08:12:35'}
|
||||||
|
|
||||||
|
monkeypatch.setattr(inquirer, 'prompt', mockreturn)
|
||||||
|
|
||||||
|
args = (
|
||||||
|
'--key',
|
||||||
|
'date_original',
|
||||||
|
str(self.src_path.joinpath('test_exif/photo.png')),
|
||||||
|
str(self.src_path),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assert_cli(cli._edit, args)
|
||||||
|
|
||||||
|
# self.assert_options(cli._edit, bool_options, arg_options, args)
|
||||||
|
# self.assert_all_options(cli._edit, bool_options, arg_options, args)
|
||||||
|
|
||||||
def test_sort(self):
|
def test_sort(self):
|
||||||
bool_options = (
|
bool_options = (
|
||||||
# '--interactive',
|
# '--interactive',
|
||||||
|
|
|
@ -251,7 +251,6 @@ class TestCollection:
|
||||||
# Summary is created and there is no errors
|
# Summary is created and there is no errors
|
||||||
assert not summary.errors
|
assert not summary.errors
|
||||||
|
|
||||||
# @pytest.mark.skip()
|
|
||||||
def test_edit_metadata(self, tmp_path, monkeypatch):
|
def test_edit_metadata(self, tmp_path, monkeypatch):
|
||||||
path = tmp_path / 'collection'
|
path = tmp_path / 'collection'
|
||||||
shutil.copytree(self.src_path, path)
|
shutil.copytree(self.src_path, path)
|
||||||
|
@ -263,7 +262,7 @@ class TestCollection:
|
||||||
|
|
||||||
monkeypatch.setattr(inquirer, 'prompt', mockreturn)
|
monkeypatch.setattr(inquirer, 'prompt', mockreturn)
|
||||||
|
|
||||||
collection.edit_metadata(path, 'date_original', overwrite=True)
|
collection.edit_metadata({path}, {'date_original'}, overwrite=True)
|
||||||
# check if db value is set
|
# check if db value is set
|
||||||
date = collection.db.sqlite.get_metadata_data('test_exif/photo.rw2',
|
date = collection.db.sqlite.get_metadata_data('test_exif/photo.rw2',
|
||||||
'DateOriginal')
|
'DateOriginal')
|
||||||
|
|
Loading…
Reference in New Issue