import json import os import pyheif import rawpy from django.shortcuts import render, get_object_or_404, reverse from django.http.response import HttpResponse, HttpResponseRedirect from django.views.decorators.cache import cache_page from PIL import Image from collection.poc import get_files from collection.models import Picture from collection.video import get_thumbnail_from_video def gather_view(request): Picture.objects.all().delete() for file in get_files(): try: Picture.objects.get(file_path=file.path, checksum=file.checksum) except Picture.DoesNotExist: Picture.objects.create( file_path=file.path, kind=Picture.VIDEO if file.is_video else Picture.PICTURE, raw=file.is_raw, creation_date=file.datetime, checksum=file.checksum, exif=json.dumps(file.exif), stat=json.dumps(file.stat), mimetype=file.mimetype, ) for file in Picture.objects.all(): if not os.path.exists(file.file_path): file.delete() return HttpResponse("ok") DEFAULT_SORT_BY = "-creation_date" SORT_BY_OPTIONS = { "creation_date": "Creation date ASC", "-creation_date": "Creation date DESC", } def list_view(request): sort_by = request.GET.get("sort_by") if sort_by not in SORT_BY_OPTIONS.keys(): return HttpResponseRedirect(reverse("list") + f"?sort_by={DEFAULT_SORT_BY}") pictures = Picture.objects.all().order_by(DEFAULT_SORT_BY) years = tuple( Picture.objects.all() .distinct("creation_date__year") .values_list("creation_date__year", flat=True) ) return render( template_name="list.html", request=request, context=dict( pictures=pictures, years=years, sort_by=sort_by, sort_by_options=SORT_BY_OPTIONS, ), ) def list_year_month(request, year: int, month: int = None): sort_by = request.GET.get("sort_by") pictures = Picture.objects.filter(creation_date__year=year) years = tuple( Picture.objects.all() .distinct("creation_date__year") .values_list("creation_date__year", flat=True) ) months = tuple( pictures.distinct("creation_date__month").values_list( "creation_date__month", flat=True ) ) if month: pictures = pictures.filter(creation_date__month=month) return render( template_name="list.html", request=request, context=dict( pictures=pictures.order_by(DEFAULT_SORT_BY), years=years, months=months, selected_year=year, selected_month=month, ), ) def detail_view(request, picture_id): picture = get_object_or_404(Picture, id=picture_id) exif = { k: v for k, v in sorted(json.loads(picture.exif).items(), key=lambda item: item[0]) } file_stat = { k: v for k, v in sorted(json.loads(picture.stat).items(), key=lambda item: item[0]) } return render( template_name="detail.html", request=request, context=dict(picture=picture, exif=exif, file_stat=file_stat), ) def image_view(request, picture_id): picture = get_object_or_404(Picture, id=picture_id) return HttpResponse(open(picture.file_path, "rb").read()) def thumbnail_view(request, picture_id): picture = get_object_or_404(Picture, id=picture_id) if picture.kind == picture.VIDEO: thumbnail = get_thumbnail_from_video(picture.file_path, picture.checksum) return HttpResponse(thumbnail, content_type="image/jpg") if picture.raw: try: with rawpy.imread(picture.file_path) as raw: # raises rawpy.LibRawNoThumbnailError if thumbnail missing # raises rawpy.LibRawUnsupportedThumbnailError if unsupported format thumb = raw.extract_thumb() if thumb.format == rawpy.ThumbFormat.JPEG: # thumb.data is already in JPEG format, save as-is return HttpResponse(thumb.data, content_type="image/jpeg") elif thumb.format == rawpy.ThumbFormat.BITMAP: # thumb.data is an RGB numpy array, convert with imageio return HttpResponse(thumb.data, content_type="image/bitmap") except rawpy.LibRawFileUnsupportedError: return HttpResponse(open("photo.png", "rb"), content_type="image/png") if picture.mimetype == "image/heic": heif_file = pyheif.read_heif(picture.file_path) image = Image.frombytes( mode=heif_file.mode, size=heif_file.size, data=heif_file.data ) image.thumbnail((480, 480)) image.save(f"/tmp/thumb-480-{picture.checksum}.jpg") return HttpResponse( open(f"/tmp/thumb-480-{picture.checksum}.jpg", "rb").read(), content_type="image/jpg", ) if picture.kind == picture.VIDEO: return HttpResponse(open("video.png", "rb"), content_type="image/png") if picture.kind == picture.PICTURE: image = Image.open(picture.file_path) image.thumbnail((480, 480)) image.save(f"/tmp/thumb-480-{picture.checksum}.jpg") return HttpResponse( open(f"/tmp/thumb-480-{picture.checksum}.jpg", "rb").read(), content_type="image/jpg", ) video_view = image_view