diff --git a/comic/migrations/0013_comicstatus_finished.py b/comic/migrations/0013_comicstatus_finished.py
new file mode 100644
index 0000000..06c4cd5
--- /dev/null
+++ b/comic/migrations/0013_comicstatus_finished.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.2 on 2016-04-04 11:28
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('comic', '0012_auto_20160401_0949'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='comicstatus',
+ name='finished',
+ field=models.BooleanField(default=False),
+ ),
+ ]
diff --git a/comic/migrations/0014_auto_20160404_1402.py b/comic/migrations/0014_auto_20160404_1402.py
new file mode 100644
index 0000000..b458aa2
--- /dev/null
+++ b/comic/migrations/0014_auto_20160404_1402.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.2 on 2016-04-04 13:02
+from __future__ import unicode_literals
+
+from django.db import migrations
+from django.db.models import Max
+
+def set_finished(apps, schema_editor):
+ comicstatus = apps.get_model('comic', 'comicstatus')
+ comicpage = apps.get_model('comic', 'ComicPage')
+ for row in comicstatus.objects.all():
+ last_page = comicpage.objects.filter(Comic=row.comic).aggregate(Max('index'))
+ if row.last_read_page == last_page['index__max']:
+ row.finished = True
+ row.save()
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('comic', '0013_comicstatus_finished'),
+ ]
+
+ operations = [
+ migrations.RunPython(set_finished, reverse_code=migrations.RunPython.noop),
+ ]
diff --git a/comic/models.py b/comic/models.py
index d16ec99..d1fd7cf 100644
--- a/comic/models.py
+++ b/comic/models.py
@@ -353,5 +353,12 @@ class ComicStatus(models.Model):
comic = models.ForeignKey(ComicBook, unique=False, null=False)
last_read_page = models.IntegerField(default=0)
unread = models.BooleanField(default=True)
+ finished = models.BooleanField(default=False)
+ @property
+ def read(self):
+ return self.last_read_page
+
+ def __str__(self):
+ return 'C:{0} P:{1}'.format(self.comic.file_name, self.last_read_page)
# TODO: add support to reference items last being read
diff --git a/comic/static/css/base.css b/comic/static/css/base.css
index 3200523..19fa66d 100644
--- a/comic/static/css/base.css
+++ b/comic/static/css/base.css
@@ -31,4 +31,12 @@ body {
max-height: 300px;
overflow: auto;
box-shadow: none;
+ }
+
+ td a {
+ display:block;
+ width:100%;
+ }
+ tr.clickable-row {
+ cursor: pointer;
}
\ No newline at end of file
diff --git a/comic/templates/base.html b/comic/templates/base.html
index 8293d1d..cacdff5 100644
--- a/comic/templates/base.html
+++ b/comic/templates/base.html
@@ -73,6 +73,7 @@
+
{% block script %}
{% endblock %}
diff --git a/comic/templates/comic/comic_list.html b/comic/templates/comic/comic_list.html
index ec7fe8a..dd367fc 100644
--- a/comic/templates/comic/comic_list.html
+++ b/comic/templates/comic/comic_list.html
@@ -3,6 +3,24 @@
{% block content %}
+
+ Comics
+
+
+ |
+ File/Folder |
+ Status |
+
+
+
+
+ |
+ loading data |
+ 1/23 |
+
+
+
+
{% endblock %}
{% block script %}
{% endblock %}
\ No newline at end of file
diff --git a/comic/urls.py b/comic/urls.py
index e4c4ef9..ad519f3 100644
--- a/comic/urls.py
+++ b/comic/urls.py
@@ -11,5 +11,7 @@ urlpatterns = [
url(r'^account/$', views.account_page, name='account'),
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'^list_json/$', views.comic_list_json, name='comic_list_json1'),
+ url(r'^list_json/(?P[\w-]+)/$', views.comic_list_json, name='comic_list_json2'),
url(r'^(?P[\w-]+)/$', views.comic_list, name='comic_list'),
]
diff --git a/comic/util.py b/comic/util.py
index f8f623e..fbc5951 100644
--- a/comic/util.py
+++ b/comic/util.py
@@ -75,6 +75,20 @@ def generate_breadcrumbs_from_menu(paths):
return output
+class DirFile:
+ def __init__(self):
+ self.name = ''
+ self.isdir = False
+ self.icon = ''
+ self.iscb = False
+ self.location = ''
+ self.label = ''
+ self.cur_page = 0
+
+ def __str__(self):
+ return self.name
+
+
def generate_directory(user, directory=False):
"""
@@ -90,7 +104,7 @@ def generate_directory(user, directory=False):
dir_path = ''
ordered_dir_list = get_ordered_dir_list(base_dir)
for file_name in ordered_dir_list:
- df = ComicBook.DirFile()
+ df = DirFile()
df.name = file_name
if path.isdir(path.join(base_dir, dir_path, file_name)):
if directory:
@@ -101,7 +115,8 @@ def generate_directory(user, directory=False):
parent__isnull=True)
df.isdir = True
df.icon = 'glyphicon-folder-open'
- df.location = urlsafe_base64_encode(d.selector.bytes)
+ df.location = '/comic/{0}/'.format(urlsafe_base64_encode(d.selector.bytes).decode())
+ df.label = generate_dir_status(user, d)
elif file_name.lower()[-4:] in ['.rar', '.zip', '.cbr', '.cbz']:
df.iscb = True
df.icon = 'glyphicon-book'
@@ -114,16 +129,18 @@ def generate_directory(user, directory=False):
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
+ df.location = '/comic/read/{0}/{1}/'.format(urlsafe_base64_encode(book.selector.bytes).decode(),
+ last_page)
if status.unread:
- df.label = 'Unread'
+ df.label = 'Unread'
elif (last_page + 1) == book.page_count:
- df.label = 'Read'
+ df.label = 'Read'
df.cur_page = last_page
else:
- label_text = '%s/%s' % \
+ label_text = '%s/%s' % \
(last_page + 1, book.page_count)
df.label = label_text
df.cur_page = last_page
@@ -133,6 +150,21 @@ def generate_directory(user, directory=False):
return files
+def generate_dir_status(user, directory):
+ cb_list = ComicBook.objects.filter(directory=directory)
+ total = cb_list.count()
+ total_read = ComicStatus.objects.filter(user=user,
+ comic__in=cb_list,
+ finished=True).count()
+ if total == 0:
+ return 'Empty'
+ elif total == total_read:
+ return 'All Read'
+ elif total_read == 0:
+ return 'Unread'
+ return '{0}/{1}'.format(total_read, total)
+
+
def get_ordered_dir_list(folder):
directories = []
files = []
diff --git a/comic/views.py b/comic/views.py
index ec67a05..dcfb258 100644
--- a/comic/views.py
+++ b/comic/views.py
@@ -1,5 +1,6 @@
import uuid
from os import path
+import json
from django.contrib.auth import login, authenticate
from django.contrib.auth.decorators import login_required, user_passes_test
@@ -7,13 +8,16 @@ from django.contrib.auth.models import User
from django.http import HttpResponse
from django.shortcuts import render, redirect, get_object_or_404
from django.utils.http import urlsafe_base64_decode
+from django.views.decorators.csrf import ensure_csrf_cookie
+from django.db.models import Max
from .forms import SettingsForm, AccountForm, EditUserForm, AddUserForm, InitialSetupForm
-from .models import Setting, ComicBook, ComicStatus, Directory
+from .models import Setting, ComicBook, ComicStatus, Directory, ComicPage
from .util import generate_breadcrumbs_from_path, generate_breadcrumbs_from_menu, \
generate_title_from_path, Menu, generate_directory, scan_directory
+@ensure_csrf_cookie
@login_required
def comic_list(request, directory_selector=False):
try:
@@ -24,8 +28,8 @@ def comic_list(request, directory_selector=False):
return redirect('/comic/settings/')
if directory_selector:
- directory_selector = uuid.UUID(bytes=urlsafe_base64_decode(directory_selector))
- directory = Directory.objects.get(selector=directory_selector)
+ selector = uuid.UUID(bytes=urlsafe_base64_decode(directory_selector))
+ directory = Directory.objects.get(selector=selector)
else:
directory = False
@@ -34,19 +38,46 @@ def comic_list(request, directory_selector=False):
if directory:
title = generate_title_from_path(directory.path)
breadcrumbs = generate_breadcrumbs_from_path(directory)
+ json_url = '/comic/list_json/{0}/'.format(directory_selector)
else:
title = generate_title_from_path('Home')
breadcrumbs = generate_breadcrumbs_from_path()
- files = generate_directory(request.user, directory)
+ json_url = '/comic/list_json/'
+ files = generate_directory(request.user)
return render(request, 'comic/comic_list.html', {
'file_list': files,
'breadcrumbs': breadcrumbs,
'menu': Menu(request.user, 'Browse'),
'title': title,
+ 'json_url': json_url
})
+@login_required
+def comic_list_json(request, directory_selector=False):
+ icon_str = ''
+ if directory_selector:
+ directory_selector = uuid.UUID(bytes=urlsafe_base64_decode(directory_selector))
+ directory = Directory.objects.get(selector=directory_selector)
+ else:
+ directory = False
+ files = generate_directory(request.user, directory)
+ response_data = dict()
+ response_data['data'] = []
+ for file in files:
+ response_data['data'].append({
+ 'icon': icon_str.format(file.icon),
+ 'name': file.name,
+ 'label': file.label,
+ 'url': file.location,
+ })
+ return HttpResponse(
+ json.dumps(response_data),
+ content_type="application/json"
+ )
+
+
@login_required
def account_page(request):
success_message = []
@@ -208,6 +239,10 @@ def read_comic(request, comic_selector, page):
status, _ = ComicStatus.objects.get_or_create(comic=book, user=request.user)
status.unread = False
status.last_read_page = page
+ if ComicPage.objects.filter(Comic=book).aggregate(Max('index'))['index__max'] == status.last_read_page:
+ status.finished = True
+ else:
+ status.finished = False
status.save()
title = 'CBWebReader - ' + book.file_name + ' - Page: ' + str(page)
context = {