# Standard library imports. from pathlib import Path from math import ceil # External library imports. import filetype # Django imports. from django.http import HttpResponseNotFound from django.conf import settings from django.utils.http import urlencode from django.shortcuts import (render, redirect) # Project imports. from .utils import make_thumbnail ########################################################################################### # CONSTANTS. # ########################################################################################### CELLS_PER_ROW = 7 ROWS_PER_PAGE = 4 IMAGES_PER_PAGE = CELLS_PER_ROW * ROWS_PER_PAGE ########################################################################################### # View functions. # ########################################################################################### def do_recursive_search(start_path, query): """ Gets all images and sub-directories inside the start_path whose name matches the given query, and then joins the results recursively by iterating in each sub-directory. """ # Get all sub-dirs and images that match the query. all_subdirs = sorted([i for i in start_path.iterdir() if i.is_dir()]) subdirs = sorted([i for i in all_subdirs if query.lower() in i.name.lower()]) images = sorted([i for i in start_path.iterdir() if i.is_file() and query.lower() in i.name.lower()]) # For all sub-directories, regardless of the query. for subdir in all_subdirs: # Do a recursive search. rec_subdirs, rec_images = do_recursive_search(subdir, query.lower()) # Join the results if any. subdirs.extend(rec_subdirs) images.extend(rec_images) return subdirs, images ########################################################################################### # View functions. # ########################################################################################### def gallery_view(request, path = None): """ Shows a list of subdirectories and image files inside the given path. The path should be inside the GALLERY_ROOT path, otherwise a 404 error will be thrown. """ def list2rows(lst, cells = CELLS_PER_ROW): """ Converts a list into a matrix with the given amount of cells per row. """ rows = [] i = 0 while i < len(lst): row = [] for c in range(cells): try: row.append(lst[i + c]) except: pass rows.append(row) i += cells return rows # Get the absolute path to show if any, else show the base gallery path. full_path = settings.GALLERY_ROOT.joinpath(path) if path is not None else settings.GALLERY_ROOT # Get the search query from the request, if any. search = request.GET.get('search', default = '') if full_path.exists(): # If the path exists then check if it points to a directory or an image. if full_path.is_dir(): if search == '': # If there is no search query then get all images and sub-directories of the current path. subdirs = sorted([i for i in full_path.iterdir() if i.is_dir()]) images = sorted([i for i in full_path.iterdir() if i.is_file() and filetype.is_image(str(i))]) else: # If there is a search query then search the current directory recursively. subdirs, images = do_recursive_search(full_path, search) # Only keep image files. images = [image for image in images if filetype.is_image(str(image))] # For every sub-directory found, prepare it's name and path for rendering. subdir_data = [] for subdir in subdirs: subdir_data.append({ 'path': '/gallery/' + str(subdir.relative_to(settings.GALLERY_ROOT)), 'name': subdir.name }) # Get the page number to show, if any. Default to the first one if unavailable or error. try: page = int(request.GET.get('page', 1)) except ValueError: page = 1 # Compute the page offset to show. num_pages = ceil((len(images) / CELLS_PER_ROW) / ROWS_PER_PAGE) page_offset = IMAGES_PER_PAGE * (page - 1) # Slice the images found with the page offset and prepare them for rendering. img_data = [] for image in images[page_offset : page_offset + IMAGES_PER_PAGE]: # Create thumbnails as needed. make_thumbnail(image) # Get the path of the image relative to the gallery root. rel_path = image.relative_to(settings.GALLERY_ROOT) # For each image, prepare it's path, thumbnail path and name for rendering. img_data.append({ 'path': '/gallery/' + str(rel_path), 'name': image.name, 'thumbnail': '/thumbs/' + str(rel_path) }) # Rendering context. context = { 'path': path, 'subdirs': list2rows(subdir_data), 'images': list2rows(img_data), 'pages': range(1, num_pages + 1), 'num_files': len(images), 'page': page, 'prev_page': page - 1, 'next_page': page + 1, 'num_pages': num_pages, 'search': urlencode({'search': search}) if search != '' else None, 'search_text': search } # Glorious success! return render(request, 'gallery_view.html', context) else: # If the path points to an image, then get it's real path, and parent directory path. image = Path('/imgs/').joinpath(path) img_dir = settings.GALLERY_ROOT.joinpath(path).parent # Then get all sibling images. images = sorted([i.name for i in img_dir.iterdir() if i.is_file() and filetype.is_image(str(i))]) # Get the current image's index in it's directory. index = images.index(image.name) # Get the previous and next image indices. previous = index - 1 if index > 0 else None following = index + 1 if index < len(images) - 1 else None # Set the current, previous and next images as the rendering context. context = { 'image_path': image, 'prev': images[previous] if previous is not None else None, 'next': images[following] if following is not None else None } # Glorious success! return render(request, 'image_view.html', context) else: # 404 if the path wasn't found. return HttpResponseNotFound('Not found')