diff --git a/__init__.py b/__init__.py index 4e6209c..cea2ede 100644 --- a/__init__.py +++ b/__init__.py @@ -21,6 +21,7 @@ from mediagoblin import processing +from . import ratings from .storage import _is_cachefile, _ensure_in_cache_dir @@ -64,4 +65,5 @@ def setup_plugin(): hooks = { 'setup': setup_plugin, + 'add_media_to_collection': ratings.media_added_to_collection, } diff --git a/import_files.py b/import_files.py index 8c43ec9..37e5aa1 100644 --- a/import_files.py +++ b/import_files.py @@ -52,6 +52,7 @@ from mediagoblin.tools.text import convert_to_tag_list_of_dicts from mediagoblin.user_pages.lib import add_media_to_collection +from . import ratings CACHE_DIR = 'mg_cache' @@ -142,6 +143,10 @@ def handle(self): if not entry: continue added_entries.append(entry) + rating = ratings.get_rating(path) + if rating: + self.add_to_collection('rating:{}'.format(rating), + [entry]) self.add_to_collection(u'roll:{}'.format(folder_path), added_entries) diff --git a/metadata.py b/metadata.py new file mode 100644 index 0000000..cb3eddb --- /dev/null +++ b/metadata.py @@ -0,0 +1,65 @@ +import os + +import pyexiv2 + + +class Metadata(object): + lookups = { + 'rating': ('Xmp.xmp.Rating', ), + } + + def __init__(self, path): + self.path = path + self.md = pyexiv2.ImageMetadata(path) + self.dirty = False + + self.read() + + def read(self): + self.md.read() + + def save(self): + if self.dirty: + self.md.write() + self.dirty = False + + def _get_metadata_item(self, lookup): + existing_keys = self.md.keys() + for key in self.lookups[lookup]: + if key in existing_keys: + return self.md.get(key) + + @property + def rating(self): + tag = self._get_metadata_item('rating') + return tag.value if tag else None + + @rating.setter + def rating(self, value): + tag = self._get_metadata_item('rating') + if tag is None: + tag_key = self.lookups['rating'][0] + tag = pyexiv2.XmpTag(tag_key, value) + self.md[tag_key] = tag + else: + tag.value = value + self.dirty = True + + @classmethod + def from_potential_sidecar(self, filepath): + xmp_filepath = u'{}.xmp'.format(filepath) + if os.path.exists(xmp_filepath): + return Metadata(xmp_filepath) + return Metadata(filepath) + + +if __name__ == '__main__': + import sys + path = sys.argv[1].decode('utf8') + md = Metadata.from_potential_sidecar(path) + print md.path + print u" rating:", md.rating + if len(sys.argv) > 2: + md.rating = int(sys.argv[2]) + md.save() + print u" set rating to:", md.rating diff --git a/ratings.py b/ratings.py new file mode 100644 index 0000000..6049ba0 --- /dev/null +++ b/ratings.py @@ -0,0 +1,41 @@ +#from sqlalchemy import event +# +#from mediagoblin.db.models import MediaEntry +# +#@event.listens_for(MediaEntry.collections, 'append') +#def test(target, value, initiator): +# print "RECV event" +# import ipdb; ipdb.set_trace() + +import re + +from mediagoblin import mg_globals as mgg + +from .metadata import Metadata + + +def media_added_to_collection(collection, media_entry, note): + m = re.match(r'rating:(\d+)', collection.title) + if not m: + return + rating_number = int(m.group(1)) + set_rating_from_media_entry(media_entry, rating_number) + + +def set_rating_from_media_entry(media_entry, rating): + filepath = (mgg.public_store + ._cachefile_to_original_filepath( + media_entry.media_files['original'])) + path = mgg.public_store._resolve_filepath(filepath) + set_rating(path) + + +def set_rating(path, rating): + md = Metadata.from_potential_sidecar(path) + md.rating = rating + md.save() + + +def get_rating(path): + md = Metadata.from_potential_sidecar(path) + return md.rating diff --git a/storage.py b/storage.py index 6c26cd7..3ea91a9 100644 --- a/storage.py +++ b/storage.py @@ -48,6 +48,16 @@ class PersistentFileStorage(BasicFileStorage): Local filesystem implementation of storage API that doesn't delete files """ + def _cachefile_to_original_filepath(self, filepath): + """ + Custom function taking a cache file and returns original filepath. + """ + if CACHE_DIR == filepath[0]: + filepath = filepath[1:] + filename = self._re_raw_from_preview.sub(r'\1.\2', filepath[-1]) + return list(filepath[:-1]) + [filename] + _re_raw_from_preview = re.compile(r'^(.*)\.(nef|cr2)(\.jpg)$', re.I) + def _resolve_filepath(self, filepath): """ Transform the given filepath into a local filesystem path. @@ -108,7 +118,7 @@ def get_file(self, filepath, mode='r'): mode = mode.replace("w", "r") # Grab and return the file in the mode specified return PersistentStorageObjectWrapper( - open(self._resolve_filepath(filepath), mode)) + open(self._resolve_filepath(filepath), mode)) def delete_file(self, filepath): _log.info(u'Not removing {0} as requested.'.format(