From 041e2a6e42ef5716c37eb604e76aecb692774e5f Mon Sep 17 00:00:00 2001 From: Xevion Date: Sat, 31 Oct 2020 23:01:59 -0500 Subject: [PATCH] specific thumbnail generation view + manual refresh thumbnail generation, progress bar with error handling and thumbnail deletion --- viewer/migrations/0006_file_thumbnail.py | 18 +++++++++ viewer/models.py | 47 +++++++++++++++++++++++- viewer/urls.py | 4 +- viewer/views.py | 10 ++++- 4 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 viewer/migrations/0006_file_thumbnail.py diff --git a/viewer/migrations/0006_file_thumbnail.py b/viewer/migrations/0006_file_thumbnail.py new file mode 100644 index 0000000..1d7f0bb --- /dev/null +++ b/viewer/migrations/0006_file_thumbnail.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.2 on 2020-11-01 03:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('viewer', '0005_serveddirectory_known_subdirectories'), + ] + + operations = [ + migrations.AddField( + model_name='file', + name='thumbnail', + field=models.CharField(default=None, max_length=160, null=True, verbose_name='Thumbnail Filename'), + ), + ] diff --git a/viewer/models.py b/viewer/models.py index a86bdd8..b167910 100644 --- a/viewer/models.py +++ b/viewer/models.py @@ -7,6 +7,8 @@ from django.db import models from django.urls import reverse from easy_thumbnails.alias import aliases +from viewer import helpers + if not aliases.get('small'): aliases.set('small', {'size': (150, 80), 'crop': True}) @@ -34,16 +36,22 @@ class ServedDirectory(models.Model): # TODO: Implement separate recursive file matching implementation # TODO: Implement RegEx filtering step directories = [] - for file in os.listdir(self.path): + files = os.listdir(self.path) + for i, file in enumerate(files): + print(f'{i} / {len(files)}') file_path = os.path.join(self.path, file) if os.path.isfile(file_path): # Check if the file has been entered before + entry: File entry = self.files.filter(filename__exact=file).first() if entry is None: # create the file entry entry = File.create(full_path=file_path, parent=self) entry.save() + else: + if entry.thumbnail is None: + entry.generate_thumbnail() else: # directory found, remember it directories.append(file_path) @@ -60,6 +68,7 @@ class File(models.Model): filename = models.CharField('Filename', max_length=160) mediatype = models.CharField('Mediatype', max_length=30) directory = models.ForeignKey(ServedDirectory, on_delete=models.CASCADE, related_name='files') + thumbnail = models.CharField('Thumbnail Filename', max_length=160, null=True, default=None) @classmethod def create(cls, full_path: str, parent: ServedDirectory) -> 'File': @@ -75,6 +84,42 @@ class File(models.Model): """Retrieve the direct URL for a given file.""" return reverse('file', args=(directory.id, self.filename)) + def delete_thumbnail(self) -> None: + if self.thumbnail: + try: + os.remove(os.path.join(self.thumbs_dir, self.thumbnail)) + self.thumbnail = None + self.save() + except FileNotFoundError: + pass + + @property + def thumbnail_url(self): + if self.thumbnail: + return f'/thumbnails/{self.thumbnail}' + return '' + + @property + def thumbs_dir(self): + return os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static', 'thumbnails') + + def generate_thumbnail(self) -> None: + # TODO: Add django-background-task scheduling + + self.delete_thumbnail() + + thumb_file = f'{uuid.uuid4()}.jpeg' + self.thumbnail = thumb_file + + # Generate thumbnail + try: + helpers.generate_thumbnail(self.path, os.path.join(self.thumbs_dir, self.thumbnail)) + except Exception: + print(f'Could not thumbnail: {self.filename}') + self.delete_thumbnail() + + self.save() + @staticmethod def get_mediatype(path) -> str: """Simple media type categorization based on the given path.""" diff --git a/viewer/urls.py b/viewer/urls.py index 89e1f40..c63ee4d 100644 --- a/viewer/urls.py +++ b/viewer/urls.py @@ -7,6 +7,8 @@ urlpatterns = [ path('add/', views.add, name='add'), path('add/submit', views.submit_new, name='add_submit'), path('/', views.browse, name='browse'), + path('/refresh', views.refresh, name='refresh'), path('//', views.file, name='file'), - path('/refresh', views.refresh, name='refresh') + path('//generate', views.generate_thumb, name='generate_thumb'), + ] diff --git a/viewer/views.py b/viewer/views.py index 7fc9a99..0d9fc4f 100644 --- a/viewer/views.py +++ b/viewer/views.py @@ -4,7 +4,7 @@ from django.http import FileResponse, HttpResponseRedirect from django.shortcuts import render, get_object_or_404 from django.urls import reverse -from viewer.models import ServedDirectory +from viewer.models import ServedDirectory, File def index(request): @@ -93,3 +93,11 @@ def submit_new(request): 'message': 'The directory you specified was not a valid directory, either it doesn\'t ' 'exist or it isn\'t a directory.'}) return HttpResponseRedirect(reverse('browse', args=(s.id,))) + + +def generate_thumb(request, directory_id, file: str): + """View for regenerating a thumbnail for a specific file.""" + directory = get_object_or_404(ServedDirectory, id=directory_id) + file = directory.files.filter(filename=file).first() + file.generate_thumbnail() + return HttpResponseRedirect(reverse('browse', args=(directory.id,)))