Repository: librephotos/librephotos
Issue: Unable to view photos

When clicking on a photo to view, the lightbox should open showing the larger version of the photo. The front end makes a call to _/api/photos/aadd85dc9c9c91dd65d319a806b94a7b1/_ and returns a 500 error and the lightbox sits waiting to load the image.

The following error is displayed in the backend log:

> Running backend server...
[2021-01-08 14:41:26 +0000] [309] [INFO] Starting gunicorn 20.0.4
[2021-01-08 14:41:26 +0000] [309] [INFO] Listening at: http://0.0.0.0:8001 (309)
[2021-01-08 14:41:26 +0000] [309] [INFO] Using worker: gevent
[2021-01-08 14:41:26 +0000] [313] [INFO] Booting worker with pid: 313
[2021-01-08 14:41:26 +0000] [314] [INFO] Booting worker with pid: 314
14:41:37 Worker rq:worker:86d2de7e24b24bf0a4a132ffca5af635: started, version 1.6.1
14:41:37 Subscribing to channel rq:pubsub:86d2de7e24b24bf0a4a132ffca5af635
14:41:37 *** Listening on default...
14:41:37 Cleaning registries for queue: default
Not Found: /api/jobs/
Not Found: /api/jobs/
Bad Request: /api/nextcloud/listdir/
127.0.0.1 - - [2021-01-08 14:43:48] "POST /build/ HTTP/1.1" 200 139 0.044669
Internal Server Error: /api/photos/aadd85dc9c9c91dd65d319a806b94a7b1/
Traceback (most recent call last):
  File "/miniconda/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/miniconda/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/miniconda/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/miniconda/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/miniconda/lib/python3.8/site-packages/rest_framework/viewsets.py", line 125, in view
    return self.dispatch(request, *args, **kwargs)
  File "/miniconda/lib/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "/miniconda/lib/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/miniconda/lib/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
    raise exc
  File "/miniconda/lib/python3.8/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "/miniconda/lib/python3.8/site-packages/rest_framework_extensions/cache/decorators.py", line 54, in inner
    return this.process_cache_response(
  File "/miniconda/lib/python3.8/site-packages/rest_framework_extensions/cache/decorators.py", line 83, in process_cache_response
    response = view_method(view_instance, request, *args, **kwargs)
  File "/code/api/views.py", line 193, in retrieve
    return super(PhotoViewSet, self).retrieve(*args, **kwargs)
  File "/miniconda/lib/python3.8/site-packages/rest_framework/mixins.py", line 56, in retrieve
    return Response(serializer.data)
  File "/miniconda/lib/python3.8/site-packages/rest_framework/serializers.py", line 548, in data
    ret = super().data
  File "/miniconda/lib/python3.8/site-packages/rest_framework/serializers.py", line 246, in data
    self._data = self.to_representation(self.instance)
  File "/miniconda/lib/python3.8/site-packages/rest_framework/serializers.py", line 515, in to_representation
    ret[field.field_name] = field.to_representation(attribute)
  File "/miniconda/lib/python3.8/site-packages/rest_framework/fields.py", line 1870, in to_representation
    return method(value)
  File "/code/api/serializers.py", line 107, in get_similar_photos
    res = search_similar_image(obj.owner,obj)
  File "/code/api/image_similarity.py", line 15, in search_similar_image
    np.frombuffer(bytes.fromhex(photo.encoding)), dtype=np.float32)
TypeError: fromhex() argument must be str, not None


Changed files:
api/models.py

diff --git a/api/models.py b/api/models.py
index b5f2bd1..170ff87 100755
--- a/api/models.py
+++ b/api/models.py
@@ -251,11 +251,14 @@ class Photo(models.Model):
             image.thumbnail(ownphotos.settings.THUMBNAIL_SIZE_BIG,
                             PIL.Image.ANTIALIAS)
             image_io_thumb = BytesIO()
-            
             image.save(image_io_thumb, format="JPEG")
-            self.thumbnail_big.save(self.image_hash + '.jpg',
-                                ContentFile(image_io_thumb.getvalue()))
+            self.thumbnail_big.save(
+                self.image_hash + '.jpg',
+                ContentFile(image_io_thumb.getvalue()))
             image_io_thumb.close()
+        #thumbnail already exists, add to photo
+        else:
+            self.thumbnail_big.name=os.path.join(ownphotos.settings.MEDIA_ROOT,'thumbnails_big', self.image_hash + '.jpg').strip()
 
         if not os.path.exists(os.path.join(ownphotos.settings.MEDIA_ROOT,'square_thumbnails', self.image_hash + '.jpg').strip()):
             square_thumb = ImageOps.fit(image,
@@ -267,6 +270,9 @@ class Photo(models.Model):
                 self.image_hash + '.jpg',
                 ContentFile(image_io_square_thumb.getvalue()))
             image_io_square_thumb.close()
+        #thumbnail already exists, add to photo
+        else:
+            self.square_thumbnail.name=os.path.join(ownphotos.settings.MEDIA_ROOT,'square_thumbnails', self.image_hash + '.jpg').strip()
 
         if not os.path.exists(os.path.join(ownphotos.settings.MEDIA_ROOT,'square_thumbnails_small', self.image_hash + '.jpg').strip()):
             square_thumb = ImageOps.fit(image,
@@ -278,6 +284,10 @@ class Photo(models.Model):
                 self.image_hash + '.jpg',
                 ContentFile(image_io_square_thumb.getvalue()))
             image_io_square_thumb.close()
+        #thumbnail already exists, add to photo
+        else:
+            self.square_thumbnail_small.name=os.path.join(ownphotos.settings.MEDIA_ROOT,'square_thumbnails_small', self.image_hash + '.jpg').strip()
+        self.save()
 
     def _save_image_to_db(self):
         image = PIL.Image.open(self.image_path)