174 lines
5.4 KiB
Python
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
|