Added search function.

This commit is contained in:
2023-08-21 21:20:27 -04:00
parent 1a16e9f763
commit d445d633b4
7 changed files with 211 additions and 77 deletions

View File

@@ -1,3 +0,0 @@
from django.db import models
# Create your models here.

View File

@@ -1,3 +0,0 @@
from django.db import models
# Create your models here.

View File

@@ -52,6 +52,15 @@
margin-left: 2em; margin-left: 2em;
} }
.search-btn {
border: none;
background-color: #00000000;
}
.search-box {
height: 2em;
}
/**************************************************************************** /****************************************************************************
* Grid. * * Grid. *
****************************************************************************/ ****************************************************************************/

BIN
viewer/static/imgs/find.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -8,98 +8,150 @@
</title> </title>
<link href="{% static 'css/styles.css' %}" rel="stylesheet"> <link href="{% static 'css/styles.css' %}" rel="stylesheet">
</head> </head>
<body class="background"> <body class="background">
{% if images|length > 0 %} <!-- Navigation bar. -->
<table class="fc mauto"> <table class="fc mauto">
<tr> <tr>
<!-- Home button. -->
<td> <td>
<a href="/gallery/" class="mr-2"> <a href="/gallery/" class="mr-2">
<img src="{% static 'imgs/gohome.png' %}" class="small-nav-icon"> <img src="{% static 'imgs/gohome.png' %}" class="small-nav-icon">
</a> </a>
</td> </td>
<!-- Back button. -->
{% if not search %}
<td> <td>
<a href=".." class="mr-2"> <a href=".." class="mr-2">
<img src="{% static 'imgs/back.png' %}" class="small-nav-icon"> <img src="{% static 'imgs/back.png' %}" class="small-nav-icon">
</a> </a>
</td> </td>
{% endif %}
<!-- Directory path. -->
<td> <td>
<h1 class="mr-2"> <h1 class="mr-2">
{{request.path}} - Files ({{num_files}}) {% if not search %}
{{request.path}} - Files: {{num_files}}
{% else %}
Search: {{search_text}} - Files: {{num_files}}
{% endif %}
</h1> </h1>
</td> </td>
<!-- Page links. -->
{% if num_pages > 1 %} {% if num_pages > 1 %}
<td> <td>
<div class="mauto"> <div class="mauto">
{% for page in pages %}<a href="./?page={{page}}">{{page}}</a>{% if not forloop.last %}<span> </span>{% endif %}{% endfor %} {% for page in pages %}<a href="./?page={{page}}{%if search %}&{{search}}{% endif %}">{{page}}</a>{% if not forloop.last %}<span> </span>{% endif %}{% endfor %}
</div> </div>
</td> </td>
{% endif %} {% endif %}
</tr> </tr>
</table> </table>
<div class="centered-container">
<!-- Search form. -->
{% if not search %}
<form action="{% url 'gallery_view_root' %}" method="GET">
<table class="fc mauto"> <table class="fc mauto">
<tr> <tr>
{% if page != 1 %} <!-- Search title. -->
<td class="fc"> <td>
<a href="./?page={{prev_page}}"> <h3>
<img src="{% static 'imgs/back.png' %}" class="navigation-icon"> Search:
</a> </h3>
</td> </td>
{% endif %}
<td class="fc"> <!-- Search bar. -->
<table class="mauto"> <td>
<tbody> <input type="text" name="search" class="search-box">
{% for row in images %}
<tr>
{% for cell in row %}
<td class="column">
<a href="{{cell.path}}">
<img src="{{cell.thumbnail}}">
<br>
<span>
{{cell.path|truncatechars:15}}
</span>
</a>
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</td> </td>
{% if page != num_pages %}
<td class="fc"> <!-- Search submit. -->
<a href="./?page={{next_page}}"> <td>
<img src="{% static 'imgs/forward.png' %}" class="navigation-icon"> <button type="submit" class="search-btn">
</a> <img src="{% static 'imgs/find.png' %}" class="small-nav-icon">
</button>
</td> </td>
{% endif %}
</tr> </tr>
</table> </table>
</div> </form>
{% endif %} {% endif %}
<!-- Images in current directory. -->
{% if images|length > 0 %}
<table class="fc mauto">
<tr>
<!-- Previous page button. -->
{% if page != 1 %}
<td class="fc">
<a href="./?page={{prev_page}}{%if search %}&{{search}}{% endif %}">
<img src="{% static 'imgs/back.png' %}" class="navigation-icon">
</a>
</td>
{% endif %}
<!-- Image rows. -->
<td class="fc">
<table class="mauto">
<tbody>
{% for row in images %}
<tr>
{% for image in row %}
<td class="column">
<a href="{{image.path}}">
<!-- Thumbnail. -->
<img src="{{image.thumbnail}}">
<br>
<!-- Image name. -->
<span>
{{image.name|truncatechars:15}}
</span>
</a>
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</td>
<!-- Next page button. -->
{% if page != num_pages %}
<td class="fc">
<a href="./?page={{next_page}}{%if search %}&{{search}}{% endif %}">
<img src="{% static 'imgs/forward.png' %}" class="navigation-icon">
</a>
</td>
{% endif %}
</tr>
</table>
{% endif %}
{% if subdirs|length > 0 %} {% if subdirs|length > 0 %}
<!-- Sub-directories title. -->
<div class="centered-container"> <div class="centered-container">
<h1> <h1>
Sub-directories Sub-directories
</h1> </h1>
</div> </div>
<!-- Sub-directory rows. -->
<div class="centered-container"> <div class="centered-container">
<table class="mauto"> <table class="mauto">
<tbody> <tbody>
{% for row in subdirs %} {% for row in subdirs %}
<tr> <tr>
{% for cell in row %} {% for subdir in row %}
<td class="column"> <td class="column">
{% if request.path == '/gallery/' %} <a href="{{subdir.path}}">
<a href="{{cell.name}}">
{% else %}
<a href="{{request.path}}{{cell.name}}">
{% endif %}
<img src="{% static 'imgs/folder-pictures.png' %}"> <img src="{% static 'imgs/folder-pictures.png' %}">
<br> <br>
<span> <span>
{{cell.name}} {{subdir.name}}
</span> </span>
</a> </a>
</td> </td>

View File

@@ -8,14 +8,19 @@
</title> </title>
<link href="{% static 'css/styles.css' %}" rel="stylesheet"> <link href="{% static 'css/styles.css' %}" rel="stylesheet">
</head> </head>
<body class="background"> <body class="background">
<!-- Navigation. -->
<table class="fc mauto"> <table class="fc mauto">
<tr> <tr>
<!-- Home button. -->
<td> <td>
<a href="/gallery/"> <a href="/gallery/">
<img src="{% static 'imgs/gohome.png' %}" class="small-nav-icon"> <img src="{% static 'imgs/gohome.png' %}" class="small-nav-icon">
</a> </a>
</td> </td>
<!-- Back button. -->
<td> <td>
<a href=".."> <a href="..">
<img src="{% static 'imgs/back.png' %}" class="small-nav-icon"> <img src="{% static 'imgs/back.png' %}" class="small-nav-icon">
@@ -23,8 +28,11 @@
</td> </td>
</tr> </tr>
</table> </table>
<!-- Image view. -->
<table class="fc mauto"> <table class="fc mauto">
<tr> <tr>
<!-- Previous image. -->
<td> <td>
{% if prev %} {% if prev %}
<a href="../{{prev}}"> <a href="../{{prev}}">
@@ -32,6 +40,8 @@
</a> </a>
{% endif %} {% endif %}
</td> </td>
<!-- Current image. -->
<td> <td>
<div class="image-container"> <div class="image-container">
<a href="{{image_path}}" target="_blank"> <a href="{{image_path}}" target="_blank">
@@ -39,6 +49,8 @@
</a> </a>
</div> </div>
</td> </td>
<!-- Next image. -->
<td> <td>
{% if next %} {% if next %}
<a href="../{{next}}"> <a href="../{{next}}">

View File

@@ -6,10 +6,11 @@ from math import ceil
import filetype import filetype
# Django imports. # Django imports.
from django.http import HttpResponseNotFound from django.http import HttpResponseNotFound
from django.conf import settings from django.conf import settings
from django.shortcuts import (render, from django.utils.http import urlencode
redirect) from django.shortcuts import (render,
redirect)
# Project imports. # Project imports.
from .utils import make_thumbnail from .utils import make_thumbnail
@@ -26,6 +27,31 @@ IMAGES_PER_PAGE = CELLS_PER_ROW * ROWS_PER_PAGE
# View functions. # # 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.
subdirs = sorted([i.absolute() for i in start_path.iterdir() if i.is_dir() and query.lower() in i.name.lower()])
images = sorted([i for i in start_path.iterdir() if i.is_file() and filetype.is_image(str(i)) and query.lower() in i.name.lower()])
# For all sub-directories, regardless of the query.
for subdir in sorted([i for i in start_path.iterdir() if i.is_dir()]):
# 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): def gallery_view(request, path = None):
""" """
Shows a list of subdirectories and image files inside the given path. Shows a list of subdirectories and image files inside the given path.
@@ -33,6 +59,10 @@ def gallery_view(request, path = None):
""" """
def list2rows(lst, cells = CELLS_PER_ROW): def list2rows(lst, cells = CELLS_PER_ROW):
"""
Converts a list into a matrix with the given amount of cells per row.
"""
rows = [] rows = []
i = 0 i = 0
while i < len(lst): while i < len(lst):
@@ -46,64 +76,101 @@ def gallery_view(request, path = None):
i += cells i += cells
return rows 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 full_path = settings.GALLERY_ROOT.joinpath(path) if path is not None else settings.GALLERY_ROOT
if full_path.exists(): # Get the search query from the request, if any.
if full_path.is_dir(): search = request.GET.get('search', default = '')
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))])
img_data = []
num_pages = ceil((len(images) / CELLS_PER_ROW) / ROWS_PER_PAGE)
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)
# 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: try:
page = int(request.GET.get('page', 1)) page = int(request.GET.get('page', 1))
except ValueError: except ValueError:
page = 1 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) 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]: for image in images[page_offset : page_offset + IMAGES_PER_PAGE]:
# Create thumbnails as needed.
make_thumbnail(image) make_thumbnail(image)
img_context = { # Get the path of the image relative to the gallery root.
'path': image.name, 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, 'name': image.name,
'thumbnail': '/thumbs/' + path + '/' + image.name if path is not None else '/thumbs/' + image.name 'thumbnail': '/thumbs/' + str(rel_path)
} })
img_data.append(img_context)
print(page)
# Rendering context.
context = { context = {
'path': path, 'path': path,
'subdirs': list2rows(subdirs), 'subdirs': list2rows(subdir_data),
'images': list2rows(img_data), 'images': list2rows(img_data),
'pages': range(1, num_pages + 1), 'pages': range(1, num_pages + 1),
'num_files': len(images), 'num_files': len(images),
'page': page, 'page': page,
'prev_page': page - 1, 'prev_page': page - 1,
'next_page': page + 1, 'next_page': page + 1,
'num_pages': num_pages 'num_pages': num_pages,
'search': urlencode({'search': search}) if search != '' else None,
'search_text': search
} }
# Glorious success!
return render(request, 'gallery_view.html', context) return render(request, 'gallery_view.html', context)
else: else:
# If the path points to an image, then get it's real path, and parent directory path.
image = Path('/imgs/').joinpath(path) image = Path('/imgs/').joinpath(path)
img_dir = settings.GALLERY_ROOT.joinpath(path).parent 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))]) 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) index = images.index(image.name)
# Get the previous and next image indices.
previous = index - 1 if index > 0 else None previous = index - 1 if index > 0 else None
following = index + 1 if index < len(images) - 1 else None following = index + 1 if index < len(images) - 1 else None
# Set the current, previous and next images as the rendering context.
context = { context = {
'image_path': image, 'image_path': image,
'prev': images[previous] if previous is not None else None, 'prev': images[previous] if previous is not None else None,
'next': images[following] if following is not None else None 'next': images[following] if following is not None else None
} }
# Glorious success!
return render(request, 'image_view.html', context) return render(request, 'image_view.html', context)
else: else:
# 404 if the path wasn't found.
return HttpResponseNotFound('Not found') return HttpResponseNotFound('Not found')