This repository has been archived on 2022-10-08. You can view files and clone it, but cannot push or open issues or pull requests.
memories/memories/collection/views.py

174 lines
5.4 KiB
Python

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