228 lines
6.1 KiB
Python
228 lines
6.1 KiB
Python
# Standard library imports.
|
|
from pathlib import Path
|
|
from urllib.parse import urlencode
|
|
from functools import cmp_to_key
|
|
|
|
# Django imports.
|
|
from django.conf import settings
|
|
|
|
# Project imports.
|
|
from .utils import make_thumbnail, is_image_file
|
|
|
|
###########################################################################################
|
|
# Constants. #
|
|
###########################################################################################
|
|
|
|
SORT_OPTIONS = [
|
|
("abc", "Alphabetical A-Z"),
|
|
("cba", "Alphabetical Z-A"),
|
|
("old", "Creation date old to new"),
|
|
("new", "Creation date new to old"),
|
|
("recent", "Modification date most recent"),
|
|
("tnecer", "Modification date least recent"),
|
|
]
|
|
|
|
SORT_LABELS = dict(SORT_OPTIONS)
|
|
|
|
|
|
def normalize_sort(sort_value):
|
|
return sort_value if sort_value in SORT_LABELS else "abc"
|
|
|
|
|
|
def normalize_theme(theme_value):
|
|
return theme_value if theme_value in ("dark", "light") else "dark"
|
|
|
|
|
|
def get_creation_timestamp(path_obj):
|
|
try:
|
|
stat_data = path_obj.stat()
|
|
return getattr(stat_data, "st_birthtime", stat_data.st_ctime)
|
|
except OSError:
|
|
return 0
|
|
|
|
|
|
def get_modification_timestamp(path_obj):
|
|
try:
|
|
return path_obj.stat().st_mtime
|
|
except OSError:
|
|
return 0
|
|
|
|
|
|
def build_query(search_text):
|
|
query = {}
|
|
|
|
if search_text != "":
|
|
query["search"] = search_text
|
|
|
|
return query
|
|
|
|
|
|
def append_query(url, query_dict):
|
|
if len(query_dict) == 0:
|
|
return url
|
|
|
|
return url + "?" + urlencode(query_dict)
|
|
|
|
|
|
def gallery_url(path_obj=None, is_dir=False, query_dict=None):
|
|
if query_dict is None:
|
|
query_dict = {}
|
|
|
|
if path_obj is None:
|
|
base_url = "/gallery/"
|
|
else:
|
|
path_text = str(path_obj).replace("\\", "/")
|
|
base_url = "/gallery/" + path_text
|
|
|
|
if is_dir and not base_url.endswith("/"):
|
|
base_url += "/"
|
|
|
|
return append_query(base_url, query_dict)
|
|
|
|
|
|
def sort_images(images, sort_key):
|
|
def compare(img_a, img_b):
|
|
name_a = img_a.name.lower()
|
|
name_b = img_b.name.lower()
|
|
rel_a = str(img_a.relative_to(settings.GALLERY_ROOT)).lower()
|
|
rel_b = str(img_b.relative_to(settings.GALLERY_ROOT)).lower()
|
|
|
|
if sort_key == "abc":
|
|
if name_a < name_b:
|
|
return -1
|
|
if name_a > name_b:
|
|
return 1
|
|
|
|
elif sort_key == "cba":
|
|
if name_a > name_b:
|
|
return -1
|
|
if name_a < name_b:
|
|
return 1
|
|
|
|
elif sort_key == "old":
|
|
created_a = get_creation_timestamp(img_a)
|
|
created_b = get_creation_timestamp(img_b)
|
|
|
|
if created_a < created_b:
|
|
return -1
|
|
if created_a > created_b:
|
|
return 1
|
|
|
|
elif sort_key == "new":
|
|
created_a = get_creation_timestamp(img_a)
|
|
created_b = get_creation_timestamp(img_b)
|
|
|
|
if created_a > created_b:
|
|
return -1
|
|
if created_a < created_b:
|
|
return 1
|
|
|
|
elif sort_key == "recent":
|
|
modified_a = get_modification_timestamp(img_a)
|
|
modified_b = get_modification_timestamp(img_b)
|
|
|
|
if modified_a > modified_b:
|
|
return -1
|
|
if modified_a < modified_b:
|
|
return 1
|
|
|
|
elif sort_key == "tnecer":
|
|
modified_a = get_modification_timestamp(img_a)
|
|
modified_b = get_modification_timestamp(img_b)
|
|
|
|
if modified_a < modified_b:
|
|
return -1
|
|
if modified_a > modified_b:
|
|
return 1
|
|
|
|
if name_a < name_b:
|
|
return -1
|
|
if name_a > name_b:
|
|
return 1
|
|
if rel_a < rel_b:
|
|
return -1
|
|
if rel_a > rel_b:
|
|
return 1
|
|
return 0
|
|
|
|
return sorted(images, key=cmp_to_key(compare))
|
|
|
|
|
|
def build_breadcrumbs(path_text, query_dict):
|
|
breadcrumbs = [{"label": "Gallery", "path": gallery_url(None, True, query_dict)}]
|
|
|
|
if path_text == "":
|
|
return breadcrumbs
|
|
|
|
segments = Path(path_text).parts
|
|
current = Path("")
|
|
|
|
for segment in segments:
|
|
current = current.joinpath(segment)
|
|
breadcrumbs.append(
|
|
{"label": segment, "path": gallery_url(current, True, query_dict)}
|
|
)
|
|
|
|
return breadcrumbs
|
|
|
|
|
|
def build_sort_options(request, search_text, sort_key, theme):
|
|
options = []
|
|
|
|
for option_key, label in SORT_OPTIONS:
|
|
# Build a URL that points to the settings toggle endpoint which will
|
|
# persist the chosen sort (and optionally theme) in the user's
|
|
# UserSettings and then redirect back to the current view. Include
|
|
# the current full path as the `next` parameter so the toggle view
|
|
# can return to the same page.
|
|
query = {"next": request.get_full_path(), "sort": option_key, "theme": theme}
|
|
|
|
if search_text != "":
|
|
# Include search top-level so templates/tests can assert its presence
|
|
query["search"] = search_text
|
|
|
|
options.append(
|
|
{
|
|
"key": option_key,
|
|
"label": label,
|
|
"url": append_query("/gallery/toggle-settings/", query),
|
|
"is_active": option_key == sort_key,
|
|
}
|
|
)
|
|
|
|
return options
|
|
|
|
|
|
def get_first_image_thumbnail_url(subdir):
|
|
try:
|
|
images = sorted(
|
|
[
|
|
entry
|
|
for entry in subdir.iterdir()
|
|
if entry.is_file() and not entry.is_symlink() and is_image_file(entry)
|
|
],
|
|
key=lambda item: (
|
|
item.name.lower(),
|
|
str(item.relative_to(settings.GALLERY_ROOT)).lower(),
|
|
),
|
|
)
|
|
except OSError:
|
|
return None
|
|
|
|
if len(images) == 0:
|
|
return None
|
|
|
|
first_image = images[0]
|
|
|
|
try:
|
|
make_thumbnail(first_image)
|
|
rel_path = first_image.relative_to(settings.GALLERY_ROOT)
|
|
thumb_path = settings.THUMBNAILS_ROOT.joinpath(rel_path)
|
|
|
|
if thumb_path.exists():
|
|
return "/thumbs/" + str(rel_path).replace("\\", "/")
|
|
except Exception:
|
|
pass
|
|
|
|
return None
|