Sort gallery media by capture date instead of file name
All checks were successful
Docker / build (release) Successful in 9s

This commit is contained in:
krek0 2026-09-24 12:52:50 +02:00
parent 2f0c426dc1
commit f7415fb5f6
11 changed files with 314 additions and 33 deletions

View file

@ -26,8 +26,15 @@ from django.contrib.auth import get_user_model
from django.db.models import F, Q
from .forms import UploadForm
from .models import Gallery, Photo, Tag, Video
from .utils import generate_video_thumbnail, is_photo, is_video
from .models import DATE_FROM_FILE, DATE_FROM_VIDEO, Gallery, Photo, Tag, Video
from .utils import (
capture_date_from_upload,
capture_date_from_video,
generate_video_thumbnail,
is_photo,
is_video,
order_media_by_capture,
)
MEDIA_MODELS = {"photo": Photo, "video": Video}
@ -229,9 +236,9 @@ class GalleryDetailView(DetailView):
context["photos"] = context["photos"].filter(owner__id=self.kwargs["owner"])
context["videos"] = context["videos"].filter(owner__id=self.kwargs["owner"])
# Combine photos and videos into a single sorted list for the template
context["media_items"] = sorted(
[*context["photos"], *context["videos"]], key=lambda x: x.title
# Combine photos and videos into a single list, in capture order
context["media_items"] = order_media_by_capture(
[*context["photos"], *context["videos"]]
)
# Increment the photo view count
@ -304,7 +311,25 @@ class GalleryUpload(PermissionRequiredMixin, FormView):
kwargs["is_staff"] = self.request.user.is_staff
return kwargs
def _upload_media(self, model, file_field, file_obj, gallery, gallery_dir, owner, post_save=None):
@staticmethod
def _complete_capture_date(obj, modified_ms):
"""
Fill in the capture date that the file itself did not carry: photos get
theirs from EXIF when saved, videos from their container, and anything
still undated falls back on the file date sent by the browser.
"""
taken = source = None
if obj.date_taken is None and obj.is_video:
taken, source = capture_date_from_video(obj.file_path), DATE_FROM_VIDEO
if taken is None and obj.date_taken is None and modified_ms:
taken, source = capture_date_from_upload(modified_ms), DATE_FROM_FILE
if taken is None:
return
obj.set_capture_date(taken, source)
obj.save(update_fields=["date_taken", "date_source"])
def _upload_media(self, model, file_field, file_obj, gallery, gallery_dir, owner,
post_save=None, modified_ms=None):
"""
Create a media object, save it to the DB, schedule file save on commit.
Returns True if uploaded, False if already exists.
@ -317,11 +342,12 @@ class GalleryUpload(PermissionRequiredMixin, FormView):
with transaction.atomic():
obj.save()
obj.galleries.set([gallery])
def _save(o=obj, fp=file_path, f=file_obj, ff=file_field, ps=post_save):
def _save(o=obj, fp=file_path, f=file_obj, ff=file_field, ps=post_save, ms=modified_ms):
f.seek(0)
getattr(o, ff).save(fp, f)
if ps:
ps(o)
self._complete_capture_date(o, ms)
transaction.on_commit(_save)
return True
@ -359,11 +385,14 @@ class GalleryUpload(PermissionRequiredMixin, FormView):
uploaded_photo_name = []
already_exists = 0
files = form.cleaned_data["file_field"]
modified_ms = form.cleaned_data.get("file_modified")
for photo_file in files:
if is_photo(photo_file):
uploaded = self._upload_media(Photo, "image", photo_file, gallery, gallery_dir, owner)
uploaded = self._upload_media(Photo, "image", photo_file, gallery, gallery_dir, owner,
modified_ms=modified_ms)
elif is_video(photo_file):
uploaded = self._upload_media(Video, "file", photo_file, gallery, gallery_dir, owner, post_save=generate_video_thumbnail)
uploaded = self._upload_media(Video, "file", photo_file, gallery, gallery_dir, owner,
post_save=generate_video_thumbnail, modified_ms=modified_ms)
else:
messages.error(self.request, f"{photo_file.name} is not a recognized image or video")
jsondata["code"] = 400