From 1a37db8f2212a324431986532f9727df1de094c2 Mon Sep 17 00:00:00 2001
From: "ajurna@gmail.com"
Date: Fri, 1 Apr 2016 09:56:42 +0100
Subject: [PATCH] massive change on how files are accessed. moved from prviding
a path to using unique id's if there might have been any directory traversal
issues they should be gone now.
---
comic/admin.py | 10 +-
comic/management/__init__.py | 0
comic/management/commands/__init__.py | 0
comic/management/commands/scan_comics.py | 52 ++++
comic/migrations/0008_auto_20160331_1140.py | 49 ++++
comic/migrations/0009_auto_20160331_1140.py | 29 ++
comic/migrations/0010_auto_20160331_1140.py | 27 ++
comic/migrations/0011_auto_20160331_1141.py | 20 ++
comic/migrations/0012_auto_20160401_0949.py | 26 ++
comic/models.py | 279 ++++++++++++++------
comic/urls.py | 6 +-
comic/util.py | 119 +++++++--
comic/views.py | 83 +++---
13 files changed, 555 insertions(+), 145 deletions(-)
create mode 100644 comic/management/__init__.py
create mode 100644 comic/management/commands/__init__.py
create mode 100644 comic/management/commands/scan_comics.py
create mode 100644 comic/migrations/0008_auto_20160331_1140.py
create mode 100644 comic/migrations/0009_auto_20160331_1140.py
create mode 100644 comic/migrations/0010_auto_20160331_1140.py
create mode 100644 comic/migrations/0011_auto_20160331_1141.py
create mode 100644 comic/migrations/0012_auto_20160401_0949.py
diff --git a/comic/admin.py b/comic/admin.py
index 18a74d8..704ef6c 100644
--- a/comic/admin.py
+++ b/comic/admin.py
@@ -1,5 +1,5 @@
from django.contrib import admin
-from comic.models import Setting, ComicBook, ComicPage, ComicStatus
+from comic.models import Setting, ComicBook, ComicPage, ComicStatus, Directory
@admin.register(Setting)
@@ -17,6 +17,12 @@ class ComicPageAdmin(admin.ModelAdmin):
list_display = ('Comic', 'index', 'page_file_name', 'content_type')
list_filter = ['Comic']
+
@admin.register(ComicStatus)
class ComicStatusAdmin(admin.ModelAdmin):
- list_display = ['user', 'comic', 'last_read_page', 'unread']
\ No newline at end of file
+ list_display = ['user', 'comic', 'last_read_page', 'unread']
+
+
+@admin.register(Directory)
+class DirectoryAdmin(admin.ModelAdmin):
+ pass
diff --git a/comic/management/__init__.py b/comic/management/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/comic/management/commands/__init__.py b/comic/management/commands/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/comic/management/commands/scan_comics.py b/comic/management/commands/scan_comics.py
new file mode 100644
index 0000000..c1152c2
--- /dev/null
+++ b/comic/management/commands/scan_comics.py
@@ -0,0 +1,52 @@
+from django.core.management.base import BaseCommand
+
+from comic.models import Setting, Directory, ComicBook
+
+import os
+from os.path import isdir
+
+
+class Command(BaseCommand):
+ help = 'Scan directories to Update Comic DB'
+
+ def __init__(self):
+ super().__init__()
+ self.base_dir = Setting.objects.get(name='BASE_DIR').value
+
+ def handle(self, *args, **options):
+ self.scan_directory()
+
+ def scan_directory(self, directory=False):
+
+ """
+
+ :type directory: Directory
+ """
+ if not directory:
+ comic_dir = self.base_dir
+ else:
+ comic_dir = os.path.join(self.base_dir, directory.get_path())
+ for file in os.listdir(comic_dir):
+ if isdir(os.path.join(comic_dir, file)):
+ if directory:
+ next_directory, created = Directory.objects.get_or_create(name=file,
+ parent=directory)
+ else:
+ next_directory, created = Directory.objects.get_or_create(name=file,
+ parent__isnull=True)
+ if created:
+ next_directory.save()
+ self.scan_directory(next_directory)
+ else:
+ try:
+ if directory:
+ ComicBook.objects.get(file_name=file,
+ directory=directory)
+ else:
+ ComicBook.objects.get(file_name=file,
+ directory__isnull=True)
+ except ComicBook.DoesNotExist:
+ ComicBook.process_comic_book(file, directory)
+
+
+
diff --git a/comic/migrations/0008_auto_20160331_1140.py b/comic/migrations/0008_auto_20160331_1140.py
new file mode 100644
index 0000000..9c76dfb
--- /dev/null
+++ b/comic/migrations/0008_auto_20160331_1140.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.2 on 2016-03-31 10:40
+from __future__ import unicode_literals
+
+import datetime
+from django.db import migrations, models
+import django.db.models.deletion
+from django.utils.timezone import utc
+import uuid
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('comic', '0007_auto_20150626_1820'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Directory',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=100)),
+ ('selector', models.UUIDField(default=uuid.uuid4, null=True)),
+ ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='comic.Directory')),
+ ],
+ ),
+ migrations.AddField(
+ model_name='comicbook',
+ name='date_added',
+ field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(2016, 3, 31, 10, 40, 30, 62170, tzinfo=utc)),
+ preserve_default=False,
+ ),
+ migrations.AddField(
+ model_name='comicbook',
+ name='selector',
+ field=models.UUIDField(default=uuid.uuid4, null=True),
+ ),
+ migrations.AddField(
+ model_name='comicbook',
+ name='version',
+ field=models.IntegerField(default=0),
+ ),
+ migrations.AddField(
+ model_name='comicbook',
+ name='directory',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='comic.Directory'),
+ ),
+ ]
diff --git a/comic/migrations/0009_auto_20160331_1140.py b/comic/migrations/0009_auto_20160331_1140.py
new file mode 100644
index 0000000..7734683
--- /dev/null
+++ b/comic/migrations/0009_auto_20160331_1140.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.2 on 2016-03-31 10:40
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+import uuid
+
+
+def gen_uuid(apps, schema_editor):
+ comicbook = apps.get_model('comic', 'comicbook')
+ for row in comicbook.objects.all():
+ row.selector = uuid.uuid4()
+ row.save()
+ directory = apps.get_model('comic', 'directory')
+ for row in directory.objects.all():
+ row.selector = uuid.uuid4()
+ row.save()
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('comic', '0008_auto_20160331_1140'),
+ ]
+
+ operations = [
+ migrations.RunPython(gen_uuid, reverse_code=migrations.RunPython.noop),
+ ]
diff --git a/comic/migrations/0010_auto_20160331_1140.py b/comic/migrations/0010_auto_20160331_1140.py
new file mode 100644
index 0000000..f31a3b0
--- /dev/null
+++ b/comic/migrations/0010_auto_20160331_1140.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.2 on 2016-03-31 10:40
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+import uuid
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('comic', '0009_auto_20160331_1140'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='comicbook',
+ name='selector',
+ field=models.UUIDField(default=uuid.uuid4, unique=True),
+ ),
+ migrations.AlterField(
+ model_name='directory',
+ name='selector',
+ field=models.UUIDField(default=uuid.uuid4, unique=True),
+ ),
+ ]
diff --git a/comic/migrations/0011_auto_20160331_1141.py b/comic/migrations/0011_auto_20160331_1141.py
new file mode 100644
index 0000000..28a52df
--- /dev/null
+++ b/comic/migrations/0011_auto_20160331_1141.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.2 on 2016-03-31 10:41
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('comic', '0010_auto_20160331_1140'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='comicbook',
+ name='version',
+ field=models.IntegerField(default=1),
+ ),
+ ]
diff --git a/comic/migrations/0012_auto_20160401_0949.py b/comic/migrations/0012_auto_20160401_0949.py
new file mode 100644
index 0000000..d3fe969
--- /dev/null
+++ b/comic/migrations/0012_auto_20160401_0949.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.2 on 2016-04-01 08:49
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import uuid
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('comic', '0011_auto_20160331_1141'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='comicbook',
+ name='selector',
+ field=models.UUIDField(db_index=True, default=uuid.uuid4, unique=True),
+ ),
+ migrations.AlterField(
+ model_name='directory',
+ name='selector',
+ field=models.UUIDField(db_index=True, default=uuid.uuid4, unique=True),
+ ),
+ ]
diff --git a/comic/models.py b/comic/models.py
index 7a38462..d16ec99 100644
--- a/comic/models.py
+++ b/comic/models.py
@@ -1,13 +1,14 @@
from django.db import models
-from django.db.transaction import atomic
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.contrib.auth.models import User
from django.conf import settings
+from django.db.transaction import atomic
from comic import rarfile
-from comic.util import get_ordered_dir_list
+
+import uuid
import zipfile
-from os import path
+from os import path, listdir
if settings.UNRAR_TOOL:
rarfile.UNRAR_TOOL = settings.UNRAR_TOOL
@@ -24,13 +25,67 @@ class Setting(models.Model):
return self.__str__()
+class Directory(models.Model):
+ name = models.CharField(max_length=100)
+ parent = models.ForeignKey('Directory', null=True, blank=True)
+ selector = models.UUIDField(unique=True, default=uuid.uuid4, db_index=True)
+
+ def __str__(self):
+ return 'Directory: {0}; {1}'.format(self.name, self.parent)
+
+ @property
+ def path(self):
+ l = self.get_path_items()
+ l.reverse()
+ return path.sep.join(l)
+
+ def get_path(self):
+ l = self.get_path_items()
+ l.reverse()
+ return path.sep.join(l)
+
+ def get_path_items(self, p=False):
+ if not p:
+ p = []
+ p.append(self.name)
+ if self.parent:
+ self.parent.get_path_items(p)
+ return p
+
+ def get_path_objects(self, p=False):
+ if not p:
+ p = []
+ p.append(self)
+ if self.parent:
+ self.parent.get_path_objects(p)
+ return p
+
+ @staticmethod
+ def get_dir_from_path(file_path):
+ file_path = file_path.split(path.sep)
+ print(file_path)
+ for d in Directory.objects.filter(name=file_path[-1]):
+ print(d)
+ if d.get_path_items() == file_path:
+ return d
+
+
class ComicBook(models.Model):
file_name = models.CharField(max_length=100, unique=True)
+ date_added = models.DateTimeField(auto_now_add=True)
+ directory = models.ForeignKey(Directory, blank=True, null=True)
+ selector = models.UUIDField(unique=True, default=uuid.uuid4, db_index=True)
+ version = models.IntegerField(default=1)
def __str__(self):
return self.file_name
- def get_image(self, archive_path, page):
+ def get_image(self, page):
+ base_dir = Setting.objects.get(name='BASE_DIR').value
+ if self.directory:
+ archive_path = path.join(base_dir, self.directory.path, self.file_name)
+ else:
+ archive_path = path.join(base_dir, self.file_name)
try:
archive = rarfile.RarFile(archive_path)
except rarfile.NotRarFile:
@@ -62,120 +117,103 @@ class ComicBook(models.Model):
self.q_prev_to_directory = False
self.q_next_to_directory = False
- def nav(self, comic_path, page):
+ def nav(self, page, user):
out = self.Navigation()
out.cur_index = page
- out.cur_path = comic_path
+ out.cur_path = urlsafe_base64_encode(self.selector.bytes)
if page == 0:
- out.prev_path, out.prev_index = self.nav_get_prev_comic(comic_path)
+ out.prev_path, out.prev_index = self.nav_get_prev_comic(user)
if out.prev_index == -1:
out.q_prev_to_directory = True
else:
out.prev_index = page - 1
- out.prev_path = comic_path
+ out.prev_path = out.cur_path
if self.is_last_page(page):
- out.next_path, out.next_index = self.nav_get_next_comic(comic_path)
+ out.next_path, out.next_index = self.nav_get_next_comic(user)
if out.next_index == -1:
out.q_next_to_directory = True
else:
out.next_index = page + 1
- out.next_path = comic_path
+ out.next_path = out.cur_path
return out
- @staticmethod
- def nav_get_prev_comic(comic_path):
+ def nav_get_prev_comic(self, user):
base_dir = Setting.objects.get(name='BASE_DIR').value
- comic_path = urlsafe_base64_decode(comic_path).decode()
- directory, comic = path.split(comic_path)
- dir_list = get_ordered_dir_list(path.join(base_dir, directory))
- comic_index = dir_list.index(comic)
+ if self.directory:
+ folder = path.join(base_dir, self.directory.path)
+ else:
+ folder = base_dir
+ dir_list = ComicBook.get_ordered_dir_list(folder)
+ comic_index = dir_list.index(self.file_name)
if comic_index == 0:
- comic_path = urlsafe_base64_encode(directory.encode())
+ if self.directory:
+ comic_path = urlsafe_base64_encode(self.directory.selector.bytes)
+ else:
+ comic_path = ''
index = -1
else:
prev_comic = dir_list[comic_index - 1]
- comic_path = path.join(directory, prev_comic)
- if not path.isdir(path.join(base_dir, directory, prev_comic)):
+
+ if not path.isdir(path.join(folder, prev_comic)):
try:
- book = ComicBook.objects.get(file_name=prev_comic)
+ if self.directory:
+ book = ComicBook.objects.get(file_name=prev_comic,
+ directory=self.directory)
+ else:
+ book = ComicBook.objects.get(file_name=prev_comic,
+ directory__isnull=True)
except ComicBook.DoesNotExist:
- book = ComicBook.process_comic_book(base_dir, comic_path, prev_comic)
- index = ComicPage.objects.filter(Comic=book).count() - 1
- comic_path = urlsafe_base64_encode(comic_path.encode())
+ if self.directory:
+ book = ComicBook.process_comic_book(prev_comic, self.directory)
+ else:
+ book = ComicBook.process_comic_book(prev_comic)
+ cs, _ = ComicStatus.objects.get_or_create(comic=book, user=user)
+ index = cs.last_read_page
+ comic_path = urlsafe_base64_encode(book.selector.bytes)
else:
- comic_path = urlsafe_base64_encode(directory.encode())
+ if self.directory:
+ comic_path = urlsafe_base64_encode(self.directory.selector.bytes)
+ else:
+ comic_path = ''
index = -1
return comic_path, index
- @staticmethod
- def nav_get_next_comic(comic_path):
- base_dir = Setting.objects.get(name='BASE_DIR')
- comic_path = urlsafe_base64_decode(comic_path).decode()
- directory, comic = path.split(comic_path)
- dir_list = get_ordered_dir_list(path.join(base_dir.value, directory))
- comic_index = dir_list.index(comic)
+ def nav_get_next_comic(self, user):
+ base_dir = Setting.objects.get(name='BASE_DIR').value
+ if self.directory:
+ folder = path.join(base_dir, self.directory.path)
+ else:
+ folder = base_dir
+ dir_list = ComicBook.get_ordered_dir_list(folder)
+ comic_index = dir_list.index(self.file_name)
try:
next_comic = dir_list[comic_index + 1]
- comic_path = path.join(directory, next_comic)
- comic_path = urlsafe_base64_encode(comic_path)
- index = 0
+ try:
+ if self.directory:
+ book = ComicBook.objects.get(file_name=next_comic,
+ directory=self.directory)
+ else:
+ book = ComicBook.objects.get(file_name=next_comic,
+ directory__isnull=True)
+ except ComicBook.DoesNotExist:
+ if self.directory:
+ book = ComicBook.process_comic_book(next_comic, self.directory)
+ else:
+ book = ComicBook.process_comic_book(next_comic)
+ comic_path = urlsafe_base64_encode(book.selector.bytes)
+ cs, _ = ComicStatus.objects.get_or_create(comic=book, user=user)
+ index = cs.last_read_page
except IndexError:
- comic_path = urlsafe_base64_encode(directory)
+ if self.directory:
+ comic_path = urlsafe_base64_encode(self.directory.selector.bytes)
+ else:
+ comic_path = ''
index = -1
return comic_path, index
- @staticmethod
- def process_comic_book(base_dir, comic_path, comic_file_name):
- try:
- cbx = rarfile.RarFile(path.join(base_dir, comic_path))
- except rarfile.NotRarFile:
- cbx = zipfile.ZipFile(path.join(base_dir, comic_path))
- except zipfile.BadZipfile:
- return False
- with atomic():
- book = ComicBook(file_name=comic_file_name)
- book.save()
- i = 0
- for f in sorted([str(x) for x in cbx.namelist()], key=str.lower):
- try:
- dot_index = f.rindex('.') + 1
- except ValueError:
- continue
- ext = f.lower()[dot_index:]
- if ext in ['jpg', 'jpeg']:
- page = ComicPage(Comic=book,
- index=i,
- page_file_name=f,
- content_type='image/jpeg')
- page.save()
-
- i += 1
- elif ext == 'png':
- page = ComicPage(Comic=book,
- index=i,
- page_file_name=f,
- content_type='image/png')
- page.save()
- i += 1
- elif ext == 'bmp':
- page = ComicPage(Comic=book,
- index=i,
- page_file_name=f,
- content_type='image/bmp')
- page.save()
- i += 1
- elif ext == 'gif':
- page = ComicPage(Comic=book,
- index=i,
- page_file_name=f,
- content_type='image/gif')
- page.save()
- i += 1
- return book
-
class DirFile:
def __init__(self):
self.name = ''
@@ -192,7 +230,7 @@ class ComicBook(models.Model):
@staticmethod
def generate_directory(user, base_dir, comic_path):
files = []
- for fn in get_ordered_dir_list(path.join(base_dir, comic_path)):
+ for fn in ComicBook.get_ordered_dir_list(path.join(base_dir, comic_path)):
df = ComicBook.DirFile()
df.name = fn
if path.isdir(path.join(base_dir, comic_path, fn)):
@@ -232,6 +270,76 @@ class ComicBook(models.Model):
def page_name(self, index):
return ComicPage.objects.get(Comic=self, index=index).page_file_name
+ @staticmethod
+ def process_comic_book(comic_file_name, directory=False):
+ """
+
+ :type comic_file_name: str
+ :type directory: Directory
+ """
+ try:
+ book = ComicBook.objects.get(file_name=comic_file_name,
+ version=0)
+ book.directory = directory
+ book.version = 1
+ book.save()
+ return book
+ except ComicBook.DoesNotExist:
+ pass
+ base_dir = Setting.objects.get(name='BASE_DIR').value
+ if directory:
+ comic_full_path = path.join(base_dir, directory.get_path(), comic_file_name)
+ else:
+ comic_full_path = path.join(base_dir, comic_file_name)
+ try:
+ cbx = rarfile.RarFile(comic_full_path)
+ except rarfile.NotRarFile:
+ cbx = zipfile.ZipFile(comic_full_path)
+ except zipfile.BadZipfile:
+ return False
+ with atomic():
+ if directory:
+ book = ComicBook(file_name=comic_file_name,
+ directory=directory)
+ else:
+ book = ComicBook(file_name=comic_file_name)
+ book.save()
+ page_index = 0
+ for page_file_name in sorted([str(x) for x in cbx.namelist()], key=str.lower):
+ try:
+ dot_index = page_file_name.rindex('.') + 1
+ except ValueError:
+ continue
+ ext = page_file_name.lower()[dot_index:]
+ if ext in ['jpg', 'jpeg']:
+ content_type = 'image/jpeg'
+ elif ext == 'png':
+ content_type = 'image/png'
+ elif ext == 'bmp':
+ content_type = 'image/bmp'
+ elif ext == 'gif':
+ content_type = 'image/gif'
+ else:
+ content_type = 'text/plain'
+ page = ComicPage(Comic=book,
+ index=page_index,
+ page_file_name=page_file_name,
+ content_type=content_type)
+ page.save()
+ page_index += 1
+ return book
+
+ @staticmethod
+ def get_ordered_dir_list(folder):
+ directories = []
+ files = []
+ for item in listdir(folder):
+ if path.isdir(path.join(folder, item)):
+ directories.append(item)
+ else:
+ files.append(item)
+ return sorted(directories) + sorted(files)
+
class ComicPage(models.Model):
Comic = models.ForeignKey(ComicBook)
@@ -246,5 +354,4 @@ class ComicStatus(models.Model):
last_read_page = models.IntegerField(default=0)
unread = models.BooleanField(default=True)
-
# TODO: add support to reference items last being read
diff --git a/comic/urls.py b/comic/urls.py
index aa53442..e4c4ef9 100644
--- a/comic/urls.py
+++ b/comic/urls.py
@@ -9,7 +9,7 @@ urlpatterns = [
url(r'^settings/users/(?P[0-9]+)/$', views.user_config_page, name='users'),
url(r'^settings/users/add/$', views.user_add_page, name='users'),
url(r'^account/$', views.account_page, name='account'),
- url(r'^(?P[\w]+)/$', views.comic_list, name='comic_list'),
- url(r'^read/(?P[\w]+)/(?P[0-9]+)/$', views.read_comic, name='read_comic'),
- url(r'^read/(?P[\w]+)/(?P[0-9]+)/img$', views.get_image, name='get_image'),
+ url(r'^read/(?P[\w-]+)/(?P[0-9]+)/$', views.read_comic, name='read_comic'),
+ url(r'^read/(?P[\w-]+)/(?P[0-9]+)/img$', views.get_image, name='get_image'),
+ url(r'^(?P[\w-]+)/$', views.comic_list, name='comic_list'),
]
diff --git a/comic/util.py b/comic/util.py
index 44cdb50..dbb57d5 100644
--- a/comic/util.py
+++ b/comic/util.py
@@ -1,14 +1,15 @@
+from collections import OrderedDict
+from os import path, listdir
+
from django.utils.http import urlsafe_base64_encode
-from os import path
-from collections import OrderedDict
-import os
+from .models import ComicBook, Setting, ComicStatus, Directory
-def generate_title_from_path(path):
- if path == '':
+def generate_title_from_path(file_path):
+ if file_path == '':
return 'CBWebReader'
- return 'CBWebReader - ' + ' - '.join(path.split(os.sep))
+ return 'CBWebReader - ' + ' - '.join(file_path.split(path.sep))
class Menu:
@@ -39,19 +40,22 @@ class Breadcrumb:
return self.name
-def generate_breadcrumbs_from_path(comic_path):
+def generate_breadcrumbs_from_path(directory=False):
+ """
+
+ :type directory: Directory
+ """
output = [Breadcrumb()]
- prefix = '/comic/'
+ prefix = b'/comic/'
last = ''
- comic_path = path.normpath(comic_path)
- folders = comic_path.split(os.sep)
- for item in folders:
- if item == '.':
- continue
+ if directory:
+ folders = directory.get_path_objects()
+ else:
+ folders = []
+ for item in folders[::-1]:
bc = Breadcrumb()
- bc.name = item
- last = path.join(last, item)
- bc.url = prefix + urlsafe_base64_encode(last.encode()).decode()
+ bc.name = item.name
+ bc.url = prefix + urlsafe_base64_encode(item.selector.bytes)
output.append(bc)
return output
@@ -66,12 +70,93 @@ def generate_breadcrumbs_from_menu(paths):
return output
+def generate_directory(user, directory=False):
+ """
+
+ :type user: User
+ :type directory: Directory
+ """
+ base_dir = Setting.objects.get(name='BASE_DIR').value
+ files = []
+ if directory:
+ dir_path = directory.path
+ ordered_dir_list = get_ordered_dir_list(path.join(base_dir, directory.path))
+ else:
+ dir_path = ''
+ ordered_dir_list = get_ordered_dir_list(base_dir)
+ for file_name in ordered_dir_list:
+ df = ComicBook.DirFile()
+ df.name = file_name
+ if path.isdir(path.join(base_dir, dir_path, file_name)):
+ if directory:
+ d = Directory.objects.get(name=file_name,
+ parent=directory)
+ else:
+ d = Directory.objects.get(name=file_name,
+ parent__isnull=True)
+ df.isdir = True
+ df.icon = 'glyphicon-folder-open'
+ df.location = urlsafe_base64_encode(d.selector.bytes)
+ elif file_name.lower()[-4:] in ['.rar', '.zip', '.cbr', '.cbz']:
+ df.iscb = True
+ df.icon = 'glyphicon-book'
+ try:
+ if directory:
+ book = ComicBook.objects.get(file_name=file_name,
+ directory=directory)
+ else:
+ book = ComicBook.objects.get(file_name=file_name,
+ directory__isnull=True)
+ except ComicBook.DoesNotExist:
+ book = ComicBook.process_comic_book(file_name, directory)
+ df.location = urlsafe_base64_encode(book.selector.bytes)
+ status, _ = ComicStatus.objects.get_or_create(comic=book, user=user)
+ last_page = status.last_read_page
+ if status.unread:
+ df.label = 'Unread'
+ elif (last_page + 1) == book.page_count:
+ df.label = 'Read'
+ df.cur_page = last_page
+ else:
+ label_text = '%s/%s' % \
+ (last_page + 1, book.page_count)
+ df.label = label_text
+ df.cur_page = last_page
+
+ # df.label = 'Unprocessed'
+ files.append(df)
+ return files
+
+
def get_ordered_dir_list(folder):
directories = []
files = []
- for item in os.listdir(folder):
+ for item in listdir(folder):
if path.isdir(path.join(folder, item)):
directories.append(item)
else:
files.append(item)
return sorted(directories) + sorted(files)
+
+
+def scan_directory(directory=False):
+ """
+ TODO: Increase efficiency of this. reduce amount of queries.
+ :type directory: Directory
+ """
+ base_dir = Setting.objects.get(name='BASE_DIR').value
+ # filter(os.path.isdir, os.listdir(os.getcwd()))
+ if directory:
+ full_path = path.join(base_dir, directory.path)
+ else:
+ full_path = base_dir
+ dir_list = listdir(full_path)
+ directorys = [d for d in dir_list if path.isdir(path.join(full_path, d))]
+ for direct in directorys:
+ if directory:
+ d, created = Directory.objects.get_or_create(name=direct,
+ parent=directory)
+ else:
+ d, created = Directory.objects.get_or_create(name=direct)
+ if created:
+ d.save()
diff --git a/comic/views.py b/comic/views.py
index 12efe95..4b2ea03 100644
--- a/comic/views.py
+++ b/comic/views.py
@@ -1,20 +1,21 @@
-from django.http import HttpResponse
-from django.template import RequestContext
-from django.utils.http import urlsafe_base64_decode
-from django.shortcuts import render, redirect, get_object_or_404
+import uuid
+from os import path
+
+from django.contrib.auth import login, authenticate
from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth.models import User
-from django.contrib.auth import login, authenticate
+from django.http import HttpResponse
+from django.shortcuts import render, redirect, get_object_or_404
+from django.utils.http import urlsafe_base64_decode
-from .models import Setting, ComicBook, ComicStatus
-from .util import generate_breadcrumbs_from_path, generate_breadcrumbs_from_menu, generate_title_from_path, Menu
from .forms import SettingsForm, AccountForm, EditUserForm, AddUserForm, InitialSetupForm
-
-from os import path
+from .models import Setting, ComicBook, ComicStatus, Directory
+from .util import generate_breadcrumbs_from_path, generate_breadcrumbs_from_menu, \
+ generate_title_from_path, Menu, generate_directory, scan_directory
@login_required
-def comic_list(request, comic_path=''):
+def comic_list(request, directory_selector=False):
try:
base_dir = Setting.objects.get(name='BASE_DIR').value
except Setting.DoesNotExist:
@@ -22,16 +23,28 @@ def comic_list(request, comic_path=''):
if not path.isdir(base_dir):
return redirect('/comic/settings/')
- comic_path = urlsafe_base64_decode(comic_path).decode()
- title = generate_title_from_path(comic_path)
- files = ComicBook.generate_directory(request.user, base_dir, comic_path)
- context = {
+ if directory_selector:
+ directory_selector = uuid.UUID(bytes=urlsafe_base64_decode(directory_selector))
+ directory = Directory.objects.get(selector=directory_selector)
+ else:
+ directory = False
+
+ scan_directory(directory)
+
+ if directory:
+ title = generate_title_from_path(directory.path)
+ breadcrumbs = generate_breadcrumbs_from_path(directory)
+ else:
+ title = generate_title_from_path('Home')
+ breadcrumbs = generate_breadcrumbs_from_path()
+ files = generate_directory(request.user, directory)
+
+ return render(request, 'comic/comic_list.html', {
'file_list': files,
- 'breadcrumbs': generate_breadcrumbs_from_path(comic_path),
+ 'breadcrumbs': breadcrumbs,
'menu': Menu(request.user, 'Browse'),
'title': title,
- }
- return render(request, 'comic/comic_list.html', context)
+ })
@login_required
@@ -184,16 +197,19 @@ def settings_page(request):
@login_required
-def read_comic(request, comic_path, page):
+def read_comic(request, comic_selector, page):
base_dir = Setting.objects.get(name='BASE_DIR').value
page = int(page)
- decoded_path = urlsafe_base64_decode(comic_path).decode()
- breadcrumbs = generate_breadcrumbs_from_path(decoded_path)
- _, comic_file_name = path.split(decoded_path)
- try:
- book = ComicBook.objects.get(file_name=comic_file_name)
- except ComicBook.DoesNotExist:
- book = ComicBook.process_comic_book(base_dir, decoded_path, comic_file_name)
+ selector = uuid.UUID(bytes=urlsafe_base64_decode(comic_selector))
+ book = get_object_or_404(ComicBook, selector=selector)
+
+ breadcrumbs = generate_breadcrumbs_from_path(book.directory)
+ #comic_file_path, comic_file_name = path.split(decoded_path)
+ #d = Directory.get_dir_from_path(comic_file_path)
+ #try:
+ # book = ComicBook.objects.get(file_name=comic_file_name)
+ #except ComicBook.DoesNotExist:
+ # book = ComicBook.process_comic_book(comic_file_name, d)
status, _ = ComicStatus.objects.get_or_create(comic=book, user=request.user)
status.unread = False
status.last_read_page = page
@@ -202,7 +218,7 @@ def read_comic(request, comic_path, page):
context = {
'book': book,
'orig_file_name': book.page_name(page),
- 'nav': book.nav(comic_path, page),
+ 'nav': book.nav(page, request.user),
'breadcrumbs': breadcrumbs,
'menu': Menu(request.user),
'title': title,
@@ -211,17 +227,10 @@ def read_comic(request, comic_path, page):
@login_required
-def get_image(_, comic_path, page):
- base_dir = Setting.objects.get(name='BASE_DIR').value
- page = int(page)
- decoded_path = urlsafe_base64_decode(comic_path).decode()
- _, comic_file_name = path.split(decoded_path)
- try:
- book = ComicBook.objects.get(file_name=comic_file_name)
- except ComicBook.DoesNotExist:
- book = ComicBook.process_comic_book(base_dir, decoded_path, comic_file_name)
- full_path = path.join(base_dir, decoded_path)
- img, content = book.get_image(full_path, page)
+def get_image(_, comic_selector, page):
+ selector = uuid.UUID(bytes=urlsafe_base64_decode(comic_selector))
+ book = ComicBook.objects.get(selector=selector)
+ img, content = book.get_image(int(page))
return HttpResponse(img.read(), content_type=content)