diff --git a/ordigi/cli.py b/ordigi/cli.py index 695d5d5..8b2ee74 100755 --- a/ordigi/cli.py +++ b/ordigi/cli.py @@ -353,8 +353,6 @@ def _compare(**kwargs): '-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()) @@ -378,40 +376,53 @@ def _edit(**kwargs): } ) + editable_keys = ( + 'album', + 'camera_make', + 'camera_model', + 'city', + 'coordinates', + 'country', + # 'date_created', + 'date_media', + # 'date_modified', + 'date_original', + 'default', + 'latitude', + 'location', + 'longitude', + 'latitude_ref', + 'longitude_ref', + 'original_name', + 'state', + 'title', + ) + + if not kwargs['key']: + keys = set(editable_keys) + else: + keys = set(kwargs['key']) + 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', - ): + for key in keys: + if key not in editable_keys: LOG.error(f"key '{key}' is not valid") sys.exit(1) + if key == 'coordinates': + keys.remove('coordinates') + keys.update(['latitude', 'longitude']) + if key in ( + 'city', 'latitude', + 'location', '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: diff --git a/ordigi/collection.py b/ordigi/collection.py index db6fc9a..fb7308f 100644 --- a/ordigi/collection.py +++ b/ordigi/collection.py @@ -169,9 +169,6 @@ class FPath: 'state', 'title', ): - if item == 'location': - mask = 'default' - if metadata[mask]: part = str(metadata[mask]) elif item in 'custom': @@ -1168,22 +1165,48 @@ class Collection(SortMedias): # Check date format value = media.get_date_format(answer['value']) else: - if not answer[key].isalnum(): + value = answer['value'] + if not value.isalnum(): print("Invalid entry, use alphanumeric chars") value = inquirer.prompt(prompt, theme=self.theme) result = False if value: media.metadata[key] = value + if key == 'location': + coordinates = loc.coordinates_by_name(value) + if coordinates: + media.metadata['latitude'] = coordinates['latitude'] + media.metadata['longitude'] = coordinates['longitude'] + media.set_location_from_coordinates(loc) + # Update database self.db.add_file_data(media.metadata) # Update exif data - exif = WriteExif( - file_path, - media.metadata, - ignore_tags=self.opt['Exif']['ignore_tags'], - ) - result = exif.set_key_values(key, value) + if key in ( + 'date_original', + 'album', + 'title', + 'latitude', + 'location', + 'longitude', + 'latitude_ref', + 'longitude_ref', + ): + exif = WriteExif( + file_path, + media.metadata, + ignore_tags=self.opt['Exif']['ignore_tags'], + ) + if key == 'location': + result = exif.set_key_values( + 'latitude', media.metadata['latitude'] + ) + result = exif.set_key_values( + 'longitude', media.metadata['longitude'] + ) + else: + result = exif.set_key_values(key, value) if result: self.summary.append('update', True, file_path) else: diff --git a/ordigi/database.py b/ordigi/database.py index a4f29ab..e5a0a71 100644 --- a/ordigi/database.py +++ b/ordigi/database.py @@ -59,7 +59,7 @@ class Sqlite: 'City': 'text', 'State': 'text', 'Country': 'text', - 'Default': 'text', + 'Location': 'text', } self.tables = { diff --git a/ordigi/geolocation.py b/ordigi/geolocation.py index 629c0a3..4949b21 100644 --- a/ordigi/geolocation.py +++ b/ordigi/geolocation.py @@ -98,5 +98,4 @@ class GeoLocation: if locator_reverse is not None: return locator_reverse.raw - return None diff --git a/ordigi/media.py b/ordigi/media.py index 368aec6..7ffa5e3 100644 --- a/ordigi/media.py +++ b/ordigi/media.py @@ -303,12 +303,12 @@ class Media(ReadExif): self.loc_keys = ( 'latitude', 'longitude', + 'location', 'latitude_ref', 'longitude_ref', 'city', 'state', 'country', - 'default', ) def get_mimetype(self): @@ -510,7 +510,7 @@ class Media(ReadExif): continue label = utils.snake2camel(key) - value = db.get_metadata_data(relpath, label) + value = db.get_metadata(relpath, label) if 'date' in key: formated_data = self.get_date_format(value) else: @@ -518,10 +518,10 @@ class Media(ReadExif): self.metadata[key] = formated_data for key in 'src_dir', 'subdirs', 'filename': label = utils.snake2camel(key) - formated_data = db.get_metadata_data(relpath, label) + formated_data = db.get_metadata(relpath, label) self.metadata[key] = formated_data - return db.get_metadata_data(relpath, 'LocationId') + return db.get_metadata(relpath, 'LocationId') def _check_file(self, db, root): """Check if file_path is a subpath of root""" @@ -548,7 +548,7 @@ class Media(ReadExif): return None, None - def _set_location_from_db(self, location_id, db): + def set_location_from_db(self, location_id, db): self.metadata['location_id'] = location_id @@ -563,7 +563,7 @@ class Media(ReadExif): for key in self.loc_keys: self.metadata[key] = None - def _set_location_from_coordinates(self, loc): + def set_location_from_coordinates(self, loc): self.metadata['location_id'] = None @@ -572,11 +572,13 @@ class Media(ReadExif): self.metadata['latitude'], self.metadata['longitude'] ) self.log.debug("location: {place_name['default']}") - for key in ('city', 'state', 'country', 'default'): + for key in ('city', 'state', 'country', 'location'): # mask = 'city' # place_name = {'default': u'Sunnyvale', 'city-random': u'Sunnyvale'} if key in place_name: self.metadata[key] = place_name[key] + elif key == 'location': + self.metadata[key] = place_name['default'] else: self.metadata[key] = None else: @@ -613,7 +615,7 @@ class Media(ReadExif): relpath, db_checksum = self._check_file(db, root) if db_checksum: location_id = self._set_metadata_from_db(db, relpath) - self._set_location_from_db(location_id, db) + self.set_location_from_db(location_id, db) else: # file not in db self.metadata['src_dir'] = str(self.src_dir) @@ -623,7 +625,7 @@ class Media(ReadExif): self.metadata['filename'] = self.file_path.name self._set_metadata_from_exif() - self._set_location_from_coordinates(loc) + self.set_location_from_coordinates(loc) self.metadata['date_media'] = self.get_date_media() self.metadata['location_id'] = location_id diff --git a/tests/test_collection.py b/tests/test_collection.py index bbb35ab..332dfe3 100644 --- a/tests/test_collection.py +++ b/tests/test_collection.py @@ -251,11 +251,10 @@ class TestCollection: # Summary is created and there is no errors assert not summary.errors - def test_edit_metadata(self, tmp_path, monkeypatch): + def test_edit_date_metadata(self, tmp_path, monkeypatch): path = tmp_path / 'collection' shutil.copytree(self.src_path, path) collection = Collection(path, {'cache': False}) - # loc = GeoLocation() def mockreturn(prompt, theme): return {'value': '03-12-2021 08:12:35'} @@ -264,10 +263,34 @@ class TestCollection: collection.edit_metadata({path}, {'date_original'}, overwrite=True) # check if db value is set - date = collection.db.sqlite.get_metadata_data('test_exif/photo.rw2', - 'DateOriginal') + file_path = 'test_exif/photo.rw2' + date = collection.db.sqlite.get_metadata(file_path, 'DateOriginal') assert date == '2021-03-12 08:12:35' # Check if exif value is set - file_path = path.joinpath('test_exif/photo.rw2') - date = ExifTool(file_path).asdict()['EXIF:DateTimeOriginal'] + path_file = path.joinpath(file_path) + date = ExifTool(path_file).asdict()['EXIF:DateTimeOriginal'] assert date == '2021-03-12 08:12:35' + + def test_edit_location_metadata(self, tmp_path, monkeypatch): + path = tmp_path / 'collection' + shutil.copytree(self.src_path, path) + collection = Collection(path, {'cache': False}) + loc = GeoLocation() + + def mockreturn(prompt, theme): + return {'value': 'lyon'} + + monkeypatch.setattr(inquirer, 'prompt', mockreturn) + + collection.edit_metadata({path}, {'location'}, loc, True) + # check if db value is set + file_path = 'test_exif/photo.rw2' + location_id = collection.db.sqlite.get_metadata(file_path, 'LocationId') + location = collection.db.sqlite.get_location_data(location_id, 'Location') + assert location_id, location == 'Lyon' + # Check if exif value is set + path_file = path.joinpath(file_path) + latitude = ExifTool(path_file).asdict()['EXIF:GPSLatitude'] + longitude = ExifTool(path_file).asdict()['EXIF:GPSLongitude'] + assert latitude == 45.7578136999889 + assert longitude == 4.83201140001667 diff --git a/tests/test_database.py b/tests/test_database.py index 6d323a9..38c36dd 100644 --- a/tests/test_database.py +++ b/tests/test_database.py @@ -41,13 +41,13 @@ class TestSqlite: 'City': 'city', 'State': 'state', 'Country': 'country', - 'Default': 'default' + 'Location': 'location' } cls.sqlite.add_row('metadata', row_data) cls.sqlite.add_row('location', location_data) # cls.sqlite.add_metadata_data('filename', 'ksinslsdosic', 'original_name', 'date_original', 'album', 1) - # cls.sqlite.add_location(24.2, 7.3, 'city', 'state', 'country', 'default') + # cls.sqlite.add_location(24.2, 7.3, 'city', 'state', 'country', 'location') yield @@ -88,14 +88,22 @@ class TestSqlite: assert not self.sqlite.get_checksum('invalid') assert self.sqlite.get_checksum('file_path') == 'checksum' - def test_get_metadata_data(self): - assert not self.sqlite.get_metadata_data('invalid', 'DateOriginal') - assert self.sqlite.get_metadata_data('file_path', 'Album') == 'album' + def test_get_metadata(self): + assert not self.sqlite.get_metadata('invalid', 'DateOriginal') + assert self.sqlite.get_metadata('file_path', 'Album') == 'album' def test_add_location(self): result = tuple(self.sqlite.cur.execute("""select * from location where rowid=1""").fetchone()) - assert result == (24.2, 7.3, 'latitude_ref', 'longitude_ref', 'city', 'state', 'country', 'default') + assert result == ( + 24.2, 7.3, + 'latitude_ref', + 'longitude_ref', + 'city', + 'state', + 'country', + 'location', + ) @pytest.mark.skip('TODO') def test_get_location_data(self, LocationId, data): @@ -106,8 +114,8 @@ class TestSqlite: pass def test_get_location_nearby(self): - value = self.sqlite.get_location_nearby(24.2005, 7.3004, 'Default') - assert value == 'default' + value = self.sqlite.get_location_nearby(24.2005, 7.3004, 'Location') + assert value == 'location' @pytest.mark.skip('TODO') def test_delete_row(self, table, id):