diff --git a/home/models.py b/home/models.py deleted file mode 100644 index 71a8362..0000000 --- a/home/models.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.db import models - -# Create your models here. diff --git a/viewer/models.py b/viewer/models.py deleted file mode 100644 index 71a8362..0000000 --- a/viewer/models.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.db import models - -# Create your models here. diff --git a/viewer/static/css/styles.css b/viewer/static/css/styles.css index 47131ed..76e506b 100644 --- a/viewer/static/css/styles.css +++ b/viewer/static/css/styles.css @@ -52,6 +52,15 @@ margin-left: 2em; } +.search-btn { + border: none; + background-color: #00000000; +} + +.search-box { + height: 2em; +} + /**************************************************************************** * Grid. * ****************************************************************************/ diff --git a/viewer/static/imgs/find.png b/viewer/static/imgs/find.png new file mode 100755 index 0000000..6be3b37 Binary files /dev/null and b/viewer/static/imgs/find.png differ diff --git a/viewer/templates/gallery_view.html b/viewer/templates/gallery_view.html index 16dfa7c..7e55d2a 100644 --- a/viewer/templates/gallery_view.html +++ b/viewer/templates/gallery_view.html @@ -8,98 +8,150 @@ + - {% if images|length > 0 %} + + + + + {% if not search %} + {% endif %} + + + + {% if num_pages > 1 %} {% endif %}

- {{request.path}} - Files ({{num_files}}) + {% if not search %} + {{request.path}} - Files: {{num_files}} + {% else %} + Search: {{search_text}} - Files: {{num_files}} + {% endif %}

- {% for page in pages %}{{page}}{% if not forloop.last %} {% endif %}{% endfor %} + {% for page in pages %}{{page}}{% if not forloop.last %} {% endif %}{% endfor %}
-
+ + + {% if not search %} +
- {% if page != 1 %} - - {% endif %} - - {% if page != num_pages %} - - {% endif %}
- - - + + +

+ Search: +

- - - {% for row in images %} - - {% for cell in row %} - - {% endfor %} - - {% endfor %} - -
- - -
- - {{cell.path|truncatechars:15}} - -
-
+ + +
+ - - - + + + +
-
+ {% endif %} + + + {% if images|length > 0 %} + + + + {% if page != 1 %} + + {% endif %} + + + + + + {% if page != num_pages %} + + {% endif %} + +
+ + + + + + + {% for row in images %} + + {% for image in row %} + + {% endfor %} + + {% endfor %} + +
+ + + + +
+ + + + {{image.name|truncatechars:15}} + +
+
+
+ + + +
+ {% endif %} + {% if subdirs|length > 0 %} +

Sub-directories

+ +
{% for row in subdirs %} - {% for cell in row %} + {% for subdir in row %} diff --git a/viewer/templates/image_view.html b/viewer/templates/image_view.html index d68c8f4..b86543f 100644 --- a/viewer/templates/image_view.html +++ b/viewer/templates/image_view.html @@ -8,14 +8,19 @@ + +
- {% if request.path == '/gallery/' %} - - {% else %} - - {% endif %} +
- {{cell.name}} + {{subdir.name}}
+ + +
@@ -23,8 +28,11 @@
+ + + + + + +
{% if prev %} @@ -32,6 +40,8 @@ {% endif %} {% if next %} diff --git a/viewer/views.py b/viewer/views.py index aa32be3..dae28bf 100644 --- a/viewer/views.py +++ b/viewer/views.py @@ -6,10 +6,11 @@ from math import ceil import filetype # Django imports. -from django.http import HttpResponseNotFound -from django.conf import settings -from django.shortcuts import (render, - redirect) +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 @@ -26,6 +27,31 @@ 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. + 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): """ 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): + """ + Converts a list into a matrix with the given amount of cells per row. + """ + rows = [] i = 0 while i < len(lst): @@ -46,64 +76,101 @@ def gallery_view(request, path = None): 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 - if full_path.exists(): - if full_path.is_dir(): - 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) + # 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) + + # 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) - img_context = { - 'path': image.name, + # 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/' + path + '/' + image.name if path is not None else '/thumbs/' + image.name - } - - img_data.append(img_context) - - print(page) + 'thumbnail': '/thumbs/' + str(rel_path) + }) + # Rendering context. context = { - 'path': path, - 'subdirs': list2rows(subdirs), - '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 + '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')