-
-
+
diff --git a/cps/updater.py b/cps/updater.py
index 5907c974..5eb0e320 100644
--- a/cps/updater.py
+++ b/cps/updater.py
@@ -243,7 +243,7 @@ class Updater(threading.Thread):
@classmethod
def _stable_version_info(self):
- return {'version': '0.6.1'} # Current version
+ return {'version': '0.6.2'} # Current version
def _nightly_available_updates(self, request_method):
tz = datetime.timedelta(seconds=time.timezone if (time.localtime().tm_isdst == 0) else time.altzone)
diff --git a/cps/uploader.py b/cps/uploader.py
index 7537e7ca..fc766cf8 100644
--- a/cps/uploader.py
+++ b/cps/uploader.py
@@ -25,12 +25,12 @@ import os
from flask_babel import gettext as _
import comic
from cps import app
+
try:
from lxml.etree import LXML_VERSION as lxmlversion
except ImportError:
lxmlversion = None
-
try:
from wand.image import Image
from wand import version as ImageVersion
@@ -39,6 +39,7 @@ try:
except (ImportError, RuntimeError) as e:
app.logger.warning('cannot import Image, generating pdf covers for pdf uploads will not work: %s', e)
use_generic_pdf_cover = True
+
try:
from PyPDF2 import PdfFileReader
from PyPDF2 import __version__ as PyPdfVersion
@@ -61,6 +62,14 @@ except ImportError as e:
app.logger.warning('cannot import fb2, extracting fb2 metadata will not work: %s', e)
use_fb2_meta = False
+try:
+ from PIL import Image
+ from PIL import __version__ as PILversion
+ use_PIL = True
+except ImportError:
+ use_PIL = False
+
+
__author__ = 'lemmsh'
BookMeta = namedtuple('BookMeta', 'file_path, extension, title, author, cover, description, tags, series, series_id, languages')
@@ -138,6 +147,48 @@ def pdf_preview(tmp_file_path, tmp_dir):
if use_generic_pdf_cover:
return None
else:
+ if use_PIL:
+ try:
+ input1 = PdfFileReader(open(tmp_file_path, 'rb'), strict=False)
+ page0 = input1.getPage(0)
+ xObject = page0['/Resources']['/XObject'].getObject()
+
+ for obj in xObject:
+ if xObject[obj]['/Subtype'] == '/Image':
+ size = (xObject[obj]['/Width'], xObject[obj]['/Height'])
+ data = xObject[obj]._data # xObject[obj].getData()
+ if xObject[obj]['/ColorSpace'] == '/DeviceRGB':
+ mode = "RGB"
+ else:
+ mode = "P"
+ if '/Filter' in xObject[obj]:
+ if xObject[obj]['/Filter'] == '/FlateDecode':
+ img = Image.frombytes(mode, size, data)
+ cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.png"
+ img.save(filename=os.path.join(tmp_dir, cover_file_name))
+ return cover_file_name
+ # img.save(obj[1:] + ".png")
+ elif xObject[obj]['/Filter'] == '/DCTDecode':
+ cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.jpg"
+ img = open(cover_file_name, "wb")
+ img.write(data)
+ img.close()
+ return cover_file_name
+ elif xObject[obj]['/Filter'] == '/JPXDecode':
+ cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.jp2"
+ img = open(cover_file_name, "wb")
+ img.write(data)
+ img.close()
+ return cover_file_name
+ else:
+ img = Image.frombytes(mode, size, data)
+ cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.png"
+ img.save(filename=os.path.join(tmp_dir, cover_file_name))
+ return cover_file_name
+ # img.save(obj[1:] + ".png")
+ except Exception as ex:
+ print(ex)
+
try:
cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.jpg"
with Image(filename=tmp_file_path + "[0]", resolution=150) as img:
@@ -145,12 +196,13 @@ def pdf_preview(tmp_file_path, tmp_dir):
img.save(filename=os.path.join(tmp_dir, cover_file_name))
return cover_file_name
except PolicyError as ex:
- logger.warning('Pdf extraction forbidden by Imagemagick policy: %s', ex)
+ app.logger.warning('Pdf extraction forbidden by Imagemagick policy: %s', ex)
return None
except Exception as ex:
- logger.warning('Cannot extract cover image, using default: %s', ex)
+ app.logger.warning('Cannot extract cover image, using default: %s', ex)
return None
+
def get_versions():
if not use_generic_pdf_cover:
IVersion = ImageVersion.MAGICK_VERSION
@@ -166,7 +218,15 @@ def get_versions():
XVersion = 'v'+'.'.join(map(str, lxmlversion))
else:
XVersion = _(u'not installed')
- return {'Image Magick': IVersion, 'PyPdf': PVersion, 'lxml':XVersion, 'Wand Version': WVersion}
+ if use_PIL:
+ PILVersion = 'v' + PILversion
+ else:
+ PILVersion = _(u'not installed')
+ return {'Image Magick': IVersion,
+ 'PyPdf': PVersion,
+ 'lxml':XVersion,
+ 'Wand': WVersion,
+ 'Pillow': PILVersion}
def upload(uploadfile):
diff --git a/cps/web.py b/cps/web.py
index db899b75..e5951799 100644
--- a/cps/web.py
+++ b/cps/web.py
@@ -41,18 +41,11 @@ from sqlalchemy.sql.expression import text, func, true, false, not_
import json
import datetime
import isoLanguages
-from pytz import __version__ as pytzVersion
-from uuid import uuid4
import os.path
-import sys
-import re
-import db
-from shutil import move, copyfile
import gdriveutils
from redirect import redirect_back
from cps import lm, babel, ub, config, get_locale, language_table, app, db
from pagination import Pagination
-import unidecode
feature_support = dict()
@@ -374,7 +367,8 @@ def get_comic_book(book_id, book_format, page):
# ################################### Typeahead ##################################################################
def get_typeahead(database, query, replace=('','')):
- entries = db.session.query(database).filter(database.name.ilike("%" + query + "%")).all()
+ db.session.connection().connection.connection.create_function("lower", 1, db.lcase)
+ entries = db.session.query(database).filter(db.func.lower(database.name).ilike("%" + query + "%")).all()
json_dumps = json.dumps([dict(name=r.name.replace(*replace)) for r in entries])
return json_dumps
@@ -428,12 +422,13 @@ def get_matching_tags():
tag_dict = {'tags': []}
if request.method == "GET":
q = db.session.query(db.Books)
+ db.session.connection().connection.connection.create_function("lower", 1, db.lcase)
author_input = request.args.get('author_name')
title_input = request.args.get('book_title')
include_tag_inputs = request.args.getlist('include_tag')
exclude_tag_inputs = request.args.getlist('exclude_tag')
- q = q.filter(db.Books.authors.any(db.Authors.name.ilike("%" + author_input + "%")),
- db.Books.title.ilike("%" + title_input + "%"))
+ q = q.filter(db.Books.authors.any(db.func.lower(db.Authors.name).ilike("%" + author_input + "%")),
+ db.func.lower(db.Books.title).ilike("%" + title_input + "%"))
if len(include_tag_inputs) > 0:
for tag in include_tag_inputs:
q = q.filter(db.Books.tags.any(db.Tags.id == tag))
@@ -874,20 +869,15 @@ def advanced_search():
searchterm = " + ".join(filter(None, searchterm))
q = q.filter()
if author_name:
- q = q.filter(db.Books.authors.any(db.or_(db.Authors.name.ilike("%" + author_name + "%"),
- db.Authors.name.ilike("%" + unidecode.unidecode(author_name)
- + "%"))))
+ q = q.filter(db.Books.authors.any(db.func.lower(db.Authors.name).ilike("%" + author_name + "%")))
if book_title:
- q = q.filter(db.or_(db.Books.title.ilike("%" + book_title + "%"),
- db.Books.title.ilike("%" + unidecode.unidecode(book_title) + "%")))
+ q = q.filter(db.func.lower(db.Books.title).ilike("%" + book_title + "%"))
if pub_start:
q = q.filter(db.Books.pubdate >= pub_start)
if pub_end:
q = q.filter(db.Books.pubdate <= pub_end)
if publisher:
- q = q.filter(db.Books.publishers.any(db.or_(db.Publishers.name.ilike("%" + publisher + "%"),
- db.Publishers.name.ilike("%" + unidecode.unidecode(publisher)
- + "%"),)))
+ q = q.filter(db.Books.publishers.any(db.func.lower(db.Publishers.name).ilike("%" + publisher + "%")))
for tag in include_tag_inputs:
q = q.filter(db.Books.tags.any(db.Tags.id == tag))
for tag in exclude_tag_inputs:
@@ -910,9 +900,7 @@ def advanced_search():
rating_low = int(rating_low) * 2
q = q.filter(db.Books.ratings.any(db.Ratings.rating >= rating_low))
if description:
- q = q.filter(db.Books.comments.any(db.or_(db.Comments.text.ilike("%" + description + "%"),
- db.Comments.text.ilike("%" + unidecode.unidecode(description)
- + "%"))))
+ q = q.filter(db.Books.comments.any(db.func.lower(db.Comments.text).ilike("%" + description + "%")))
# search custom culumns
for c in cc:
@@ -927,8 +915,7 @@ def advanced_search():
db.cc_classes[c.id].value == custom_query))
else:
q = q.filter(getattr(db.Books, 'custom_column_'+str(c.id)).any(
- db.or_(db.cc_classes[c.id].value.ilike("%" + custom_query + "%"),
- db.cc_classes[c.id].value.ilike("%" + unidecode.unidecode(custom_query) + "%"))))
+ db.func.lower(db.cc_classes[c.id].value).ilike("%" + custom_query + "%")))
q = q.all()
ids = list()
for element in q:
diff --git a/requirements.txt b/requirements.txt
index 3fb23ea3..84ffdd7c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -13,3 +13,4 @@ SQLAlchemy>=1.1.0
tornado>=4.1
Wand>=0.4.4
unidecode>=0.04.19
+Pillow>=5.4.0
\ No newline at end of file