Refactoring media class (3)
This commit is contained in:
parent
8fd65fda34
commit
26845cf56b
|
@ -777,10 +777,10 @@ class Collection(SortMedias):
|
|||
def init(self, loc):
|
||||
"""Init collection db"""
|
||||
for file_path in self.get_collection_files():
|
||||
media = self.medias.get_media(file_path, self.root, loc)
|
||||
media.metadata['file_path'] = os.path.relpath(file_path, self.root)
|
||||
metadata = self.medias.get_metadata(file_path, self.root, loc)
|
||||
metadata['file_path'] = os.path.relpath(file_path, self.root)
|
||||
|
||||
self.db.add_file_data(media.metadata)
|
||||
self.db.add_file_data(metadata)
|
||||
self.summary.append('update', file_path)
|
||||
|
||||
return self.summary
|
||||
|
@ -832,22 +832,22 @@ class Collection(SortMedias):
|
|||
relpath = os.path.relpath(file_path, self.root)
|
||||
# If file not in database
|
||||
if relpath not in db_paths:
|
||||
media = self.medias.get_media(file_path, self.root, loc)
|
||||
media.metadata['file_path'] = relpath
|
||||
metadata = self.medias.get_metadata(file_path, self.root, loc)
|
||||
metadata['file_path'] = relpath
|
||||
# Check if file checksum is in invalid rows
|
||||
row = []
|
||||
for row in invalid_db_rows:
|
||||
if row['Checksum'] == media.metadata['checksum']:
|
||||
if row['Checksum'] == metadata['checksum']:
|
||||
# file have been moved without registering to db
|
||||
media.metadata['src_path'] = row['SrcPath']
|
||||
metadata['src_path'] = row['SrcPath']
|
||||
# Check if row FilePath is a subpath of relpath
|
||||
if relpath.startswith(row['FilePath']):
|
||||
path = os.path.relpath(relpath, row['FilePath'])
|
||||
media.metadata['subdirs'] = row['Subdirs'] + path
|
||||
media.metadata['Filename'] = row['Filename']
|
||||
metadata['subdirs'] = row['Subdirs'] + path
|
||||
metadata['Filename'] = row['Filename']
|
||||
break
|
||||
# set row attribute to the file
|
||||
self.db.add_file_data(media.metadata)
|
||||
self.db.add_file_data(metadata)
|
||||
self.summary.append('update', file_path)
|
||||
|
||||
# Finally delete invalid rows
|
||||
|
@ -947,14 +947,13 @@ class Collection(SortMedias):
|
|||
|
||||
# Get medias data
|
||||
subdirs = set()
|
||||
for media in self.medias.get_medias(src_dirs, imp=imp, loc=loc):
|
||||
for src_path, metadata in self.medias.get_metadatas(src_dirs, imp=imp, loc=loc):
|
||||
# Get the destination path according to metadata
|
||||
fpath = FPath(path_format, self.day_begins, self.logger)
|
||||
media.metadata['file_path'] = fpath.get_path(media.metadata)
|
||||
subdirs.add(media.file_path.parent)
|
||||
metadata['file_path'] = fpath.get_path(metadata)
|
||||
subdirs.add(src_path.parent)
|
||||
|
||||
src_path = media.file_path
|
||||
self.medias.datas[src_path] = copy(media.metadata)
|
||||
self.medias.datas[src_path] = copy(metadata)
|
||||
|
||||
# Sort files and solve conflicts
|
||||
self.summary = self.sort_medias(imp, remove_duplicates)
|
||||
|
@ -990,9 +989,8 @@ class Collection(SortMedias):
|
|||
dedup_regex = [date_num3, date_num2, default]
|
||||
|
||||
# Get medias data
|
||||
for media in self.medias.get_medias(paths):
|
||||
for src_path, metadata in self.medias.get_metadatas(paths):
|
||||
# Deduplicate the path
|
||||
src_path = media.file_path
|
||||
path_parts = src_path.relative_to(self.root).parts
|
||||
dedup_path = []
|
||||
for path_part in path_parts:
|
||||
|
@ -1005,9 +1003,8 @@ class Collection(SortMedias):
|
|||
|
||||
dedup_path.append(''.join(filtered_items))
|
||||
|
||||
media.metadata['file_path'] = os.path.join(*dedup_path)
|
||||
src_path = media.file_path
|
||||
self.medias.datas[src_path] = copy(media.metadata)
|
||||
metadata['file_path'] = os.path.join(*dedup_path)
|
||||
self.medias.datas[src_path] = copy(metadata)
|
||||
|
||||
# Sort files and solve conflicts
|
||||
self.sort_medias(remove_duplicates=remove_duplicates)
|
||||
|
@ -1027,20 +1024,18 @@ class Collection(SortMedias):
|
|||
for img_path in images.find_similar(image, similarity):
|
||||
self.paths.paths_list.append(img_path)
|
||||
|
||||
media = self.medias.get_media(img_path, path)
|
||||
metadata = self.medias.get_metadata(img_path, path)
|
||||
relpath = os.path.join(directory_name, img_path.name)
|
||||
media.metadata['file_path'] = relpath
|
||||
file_path = media.file_path
|
||||
self.medias.datas[file_path] = copy(media.metadata)
|
||||
metadata['file_path'] = relpath
|
||||
self.medias.datas[img_path] = copy(metadata)
|
||||
|
||||
if self.medias.datas:
|
||||
# Found similar images to image
|
||||
self.paths.paths_list.append(image.img_path)
|
||||
media = self.medias.get_media(image.img_path, path)
|
||||
metadata = self.medias.get_metadata(image.img_path, path)
|
||||
relpath = os.path.join(directory_name, image.img_path.name)
|
||||
media.metadata['file_path'] = relpath
|
||||
file_path = media.file_path
|
||||
self.medias.datas[file_path] = copy(media.metadata)
|
||||
metadata['file_path'] = relpath
|
||||
self.medias.datas[image.img_path] = copy(metadata)
|
||||
|
||||
return True
|
||||
|
||||
|
|
130
ordigi/media.py
130
ordigi/media.py
|
@ -69,6 +69,7 @@ class ExifMetadata:
|
|||
|
||||
|
||||
class ReadExif(ExifMetadata):
|
||||
"""Read exif metadata to file"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -94,7 +95,7 @@ class ReadExif(ExifMetadata):
|
|||
|
||||
return ExifToolCaching(self.file_path, logger=self.logger).asdict()
|
||||
|
||||
def _get_key_values(self, key):
|
||||
def get_key_values(self, key):
|
||||
"""
|
||||
Get the first value of a tag set
|
||||
:returns: str or None if no exif tag
|
||||
|
@ -106,20 +107,43 @@ class ReadExif(ExifMetadata):
|
|||
if tag in self.exif_metadata:
|
||||
yield self.exif_metadata[tag]
|
||||
|
||||
def get_value(self, tag):
|
||||
def get_coordinates(self, key, value):
|
||||
"""Get latitude or longitude value
|
||||
|
||||
:param str key: Type of coordinate to get. Either "latitude" or
|
||||
"longitude".
|
||||
:returns: float or None
|
||||
"""
|
||||
Get given value from EXIF.
|
||||
:returns: str or None
|
||||
"""
|
||||
if self.exif_metadata is None:
|
||||
return None
|
||||
if tag not in self.exif_metadata:
|
||||
if value is None:
|
||||
return None
|
||||
|
||||
return self.exif_metadata[tag]
|
||||
if isinstance(value, str) and len(value) == 0:
|
||||
# If exiftool GPS output is empty, the data returned will be a str
|
||||
# with 0 length.
|
||||
# https://github.com/jmathai/elodie/issues/354
|
||||
return None
|
||||
|
||||
# Cast coordinate to a float due to a bug in exiftool's
|
||||
# -json output format.
|
||||
# https://github.com/jmathai/elodie/issues/171
|
||||
# http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,7952.0.html # noqa
|
||||
this_coordinate = float(value)
|
||||
|
||||
direction_multiplier = 1.0
|
||||
# when self.set_gps_ref != True
|
||||
if key == 'latitude':
|
||||
if 'EXIF:GPSLatitudeRef' in self.exif_metadata:
|
||||
if self.exif_metadata['EXIF:GPSLatitudeRef'] == 'S':
|
||||
direction_multiplier = -1.0
|
||||
elif key == 'longitude':
|
||||
if 'EXIF:GPSLongitudeRef' in self.exif_metadata:
|
||||
if self.exif_metadata['EXIF:GPSLongitudeRef'] == 'W':
|
||||
direction_multiplier = -1.0
|
||||
return this_coordinate * direction_multiplier
|
||||
|
||||
|
||||
class WriteExif(ExifMetadata):
|
||||
"""Write exif metadata to file"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -140,6 +164,7 @@ class WriteExif(ExifMetadata):
|
|||
|
||||
:returns: value (str)
|
||||
"""
|
||||
# TODO overwrite mode check if fail
|
||||
return ExifTool(self.file_path, logger=self.logger).setvalue(tag, value)
|
||||
|
||||
def set_key_values(self, key, value):
|
||||
|
@ -190,17 +215,17 @@ class WriteExif(ExifMetadata):
|
|||
|
||||
if all(status):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
return False
|
||||
|
||||
def set_album_from_folder(self):
|
||||
"""Set the album attribute based on the leaf folder name
|
||||
|
||||
:returns: bool
|
||||
"""
|
||||
# TODO use tag key
|
||||
return self.set_value('Album', self.file_path.parent.name)
|
||||
|
||||
|
||||
class Media(ReadExif):
|
||||
"""
|
||||
Extract matadatas from exiftool and sort them to dict structure
|
||||
|
@ -230,61 +255,25 @@ class Media(ReadExif):
|
|||
self.album_from_folder = album_from_folder
|
||||
self.interactive = interactive
|
||||
self.logger = logger.getChild(self.__class__.__name__)
|
||||
self.metadata = None
|
||||
self.use_date_filename = use_date_filename
|
||||
self.use_file_dates = use_file_dates
|
||||
|
||||
self.theme = request.load_theme()
|
||||
|
||||
# get self.metadata
|
||||
self.get_metadata(self.file_path)
|
||||
|
||||
def get_mimetype(self):
|
||||
"""
|
||||
Get the mimetype of the file.
|
||||
:returns: str or None
|
||||
"""
|
||||
# TODO add to metadata
|
||||
mimetype = mimetypes.guess_type(self.file_path)
|
||||
if mimetype is None:
|
||||
return None
|
||||
|
||||
return mimetype[0]
|
||||
|
||||
def get_coordinates(self, key, value):
|
||||
"""Get latitude or longitude value
|
||||
|
||||
:param str key: Type of coordinate to get. Either "latitude" or
|
||||
"longitude".
|
||||
:returns: float or None
|
||||
"""
|
||||
if value is None:
|
||||
return None
|
||||
|
||||
if isinstance(value, str) and len(value) == 0:
|
||||
# If exiftool GPS output is empty, the data returned will be a str
|
||||
# with 0 length.
|
||||
# https://github.com/jmathai/elodie/issues/354
|
||||
return None
|
||||
|
||||
# Cast coordinate to a float due to a bug in exiftool's
|
||||
# -json output format.
|
||||
# https://github.com/jmathai/elodie/issues/171
|
||||
# http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,7952.0.html # noqa
|
||||
this_coordinate = float(value)
|
||||
|
||||
direction_multiplier = 1.0
|
||||
# when self.set_gps_ref != True
|
||||
if key == 'latitude':
|
||||
if 'EXIF:GPSLatitudeRef' in self.exif_metadata:
|
||||
if self.exif_metadata['EXIF:GPSLatitudeRef'] == 'S':
|
||||
direction_multiplier = -1.0
|
||||
elif key == 'longitude':
|
||||
if 'EXIF:GPSLongitudeRef' in self.exif_metadata:
|
||||
if self.exif_metadata['EXIF:GPSLongitudeRef'] == 'W':
|
||||
direction_multiplier = -1.0
|
||||
return this_coordinate * direction_multiplier
|
||||
|
||||
return None
|
||||
|
||||
def get_date_format(self, value):
|
||||
"""
|
||||
Formatting date attribute.
|
||||
|
@ -311,11 +300,12 @@ class Media(ReadExif):
|
|||
choices_list = [
|
||||
inquirer.List(
|
||||
'date_list',
|
||||
message=f"Choice appropriate original date",
|
||||
message="Choice appropriate original date",
|
||||
choices=choices,
|
||||
default=default,
|
||||
),
|
||||
]
|
||||
# import ipdb; ipdb.set_trace()
|
||||
answers = inquirer.prompt(choices_list, theme=self.theme)
|
||||
|
||||
if not answers['date_list']:
|
||||
|
@ -324,8 +314,8 @@ class Media(ReadExif):
|
|||
]
|
||||
answers = inquirer.prompt(prompt, theme=self.theme)
|
||||
return self.get_date_format(answers['date_custom'])
|
||||
else:
|
||||
return answers['date_list']
|
||||
|
||||
return answers['date_list']
|
||||
|
||||
def get_date_media(self):
|
||||
'''
|
||||
|
@ -384,17 +374,19 @@ class Media(ReadExif):
|
|||
|
||||
return date_filename
|
||||
|
||||
elif self.use_file_dates:
|
||||
if self.use_file_dates:
|
||||
if date_created:
|
||||
self.logger.warning(
|
||||
f"use date created:{date_created} for {self.file_path}"
|
||||
)
|
||||
return date_created
|
||||
elif date_modified:
|
||||
|
||||
if date_modified:
|
||||
self.logger.warning(
|
||||
f"use date modified:{date_modified} for {self.file_path}"
|
||||
)
|
||||
return date_modified
|
||||
|
||||
elif self.interactive:
|
||||
choices = []
|
||||
if date_filename:
|
||||
|
@ -441,7 +433,7 @@ class Media(ReadExif):
|
|||
|
||||
for key in self.tags_keys:
|
||||
formated_data = None
|
||||
for value in self._get_key_values(key):
|
||||
for value in self.get_key_values(key):
|
||||
if 'date' in key:
|
||||
formated_data = self.get_date_format(value)
|
||||
elif key in ('latitude', 'longitude'):
|
||||
|
@ -485,7 +477,8 @@ class Media(ReadExif):
|
|||
return db.get_metadata_data(relpath, 'LocationId')
|
||||
|
||||
def _check_file(self, db, root):
|
||||
# Check if file_path is a subpath of root
|
||||
"""Check if file_path is a subpath of root"""
|
||||
|
||||
if str(self.file_path).startswith(str(root)):
|
||||
relpath = os.path.relpath(self.file_path, root)
|
||||
db_checksum = db.get_checksum(relpath)
|
||||
|
@ -506,7 +499,7 @@ class Media(ReadExif):
|
|||
|
||||
return relpath, db_checksum
|
||||
|
||||
return
|
||||
return None, None
|
||||
|
||||
def _set_location_metadata(self, location_id, db, loc=None):
|
||||
|
||||
|
@ -653,8 +646,8 @@ class Medias:
|
|||
self.datas = {}
|
||||
self.theme = request.load_theme()
|
||||
|
||||
def get_media(self, file_path, src_dir, loc=None):
|
||||
return Media(
|
||||
def get_media(self, file_path, src_dir):
|
||||
media = Media(
|
||||
file_path,
|
||||
src_dir,
|
||||
self.album_from_folder,
|
||||
|
@ -665,7 +658,16 @@ class Medias:
|
|||
self.use_file_dates,
|
||||
)
|
||||
|
||||
def get_medias(self, src_dirs, imp=False, loc=None):
|
||||
return media
|
||||
|
||||
def get_metadata(self, file_path, src_dir, loc=None):
|
||||
media = self.get_media(file_path, src_dir)
|
||||
media.get_metadata(self.root, loc, self.db.sqlite,
|
||||
self.cache)
|
||||
|
||||
return media.metadata
|
||||
|
||||
def get_metadatas(self, src_dirs, imp=False, loc=None):
|
||||
"""Get medias data"""
|
||||
for src_dir in src_dirs:
|
||||
src_dir = self.paths.check(src_dir)
|
||||
|
@ -680,9 +682,9 @@ class Medias:
|
|||
sys.exit(1)
|
||||
|
||||
# Get file metadata
|
||||
media = self.get_media(src_path, src_dir, loc)
|
||||
metadata = self.get_metadata(src_path, src_dir, loc)
|
||||
|
||||
yield media
|
||||
yield src_path, metadata
|
||||
|
||||
def update_exif_data(self, metadata):
|
||||
|
||||
|
@ -711,5 +713,3 @@ class Medias:
|
|||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# TODO to be removed later
|
||||
from datetime import datetime
|
||||
import shutil
|
||||
import sqlite3
|
||||
|
@ -12,7 +11,7 @@ from ordigi.collection import Collection, FPath, Paths
|
|||
from ordigi.exiftool import ExifToolCaching, exiftool_is_running, terminate_exiftool
|
||||
from ordigi.geolocation import GeoLocation
|
||||
from ordigi import log
|
||||
from ordigi.media import Media
|
||||
from ordigi.media import Media, ReadExif
|
||||
from ordigi import utils
|
||||
from .conftest import randomize_files, randomize_db
|
||||
from ordigi.summary import Summary
|
||||
|
@ -65,12 +64,12 @@ class TestFPath:
|
|||
|
||||
exif_data = ExifToolCaching(str(file_path)).asdict()
|
||||
loc = GeoLocation()
|
||||
metadata = media.metadata
|
||||
media.get_metadata(self.src_path, loc)
|
||||
for item, regex in items.items():
|
||||
for mask in masks:
|
||||
matched = re.search(regex, mask)
|
||||
if matched:
|
||||
part = fpath.get_part(item, mask[1:-1], metadata)
|
||||
part = fpath.get_part(item, mask[1:-1], media.metadata)
|
||||
# check if part is correct
|
||||
assert isinstance(part, str), file_path
|
||||
if item == 'basename':
|
||||
|
@ -157,7 +156,7 @@ class TestCollection:
|
|||
for file_path in paths:
|
||||
if '.db' not in str(file_path):
|
||||
media = Media(file_path, tmp_path, album_from_folder=True)
|
||||
for value in media._get_key_values('album'):
|
||||
for value in ReadExif(file_path).get_key_values('album'):
|
||||
assert value != '' or None
|
||||
|
||||
collection = Collection(tmp_path, album_from_folder=True)
|
||||
|
@ -206,6 +205,7 @@ class TestCollection:
|
|||
# copy mode
|
||||
src_path = Path(self.src_path, 'test_exif', 'photo.png')
|
||||
media = Media(src_path, self.src_path)
|
||||
media.get_metadata(tmp_path)
|
||||
name = 'photo_' + str(imp) + '.png'
|
||||
media.metadata['file_path'] = name
|
||||
dest_path = Path(tmp_path, name)
|
||||
|
|
|
@ -52,7 +52,7 @@ class TestMedia:
|
|||
assert value is None
|
||||
|
||||
if key == 'album':
|
||||
for album in media._get_key_values('album'):
|
||||
for album in media.get_key_values('album'):
|
||||
if album is not None and album != '':
|
||||
assert value == album
|
||||
break
|
||||
|
@ -76,6 +76,7 @@ class TestMedia:
|
|||
exif_data = ExifToolCaching(str(file_path)).asdict()
|
||||
media = Media(file_path, self.src_path, use_date_filename=True,
|
||||
use_file_dates=True)
|
||||
media.get_metadata(self.src_path)
|
||||
date_media = media.get_date_media()
|
||||
|
||||
date_filename = None
|
||||
|
|
Loading…
Reference in New Issue