Commit ccf56302 authored by Radosław Kierznowski's avatar Radosław Kierznowski

Merge remote-tracking branch 'refs/remotes/janeczku/master'

parents 55ee323c 24cf550b
...@@ -22,7 +22,7 @@ except ImportError: ...@@ -22,7 +22,7 @@ except ImportError:
if __name__ == '__main__': if __name__ == '__main__':
if web.ub.DEVELOPMENT: if web.ub.DEVELOPMENT:
web.app.run(host="0.0.0.0", port=web.ub.config.config_port, debug=True) web.app.run(port=web.ub.config.config_port, debug=True)
else: else:
if gevent_present: if gevent_present:
web.app.logger.info('Attempting to start gevent') web.app.logger.info('Attempting to start gevent')
......
...@@ -67,9 +67,9 @@ class Identifiers(Base): ...@@ -67,9 +67,9 @@ class Identifiers(Base):
val = Column(String) val = Column(String)
book = Column(Integer, ForeignKey('books.id')) book = Column(Integer, ForeignKey('books.id'))
def __init__(self, val, type, book): def __init__(self, val, id_type, book):
self.val = val self.val = val
self.type = type self.type = id_type
self.book = book self.book = book
def formatType(self): def formatType(self):
...@@ -209,9 +209,9 @@ class Data(Base): ...@@ -209,9 +209,9 @@ class Data(Base):
uncompressed_size = Column(Integer) uncompressed_size = Column(Integer)
name = Column(String) name = Column(String)
def __init__(self, book, format, uncompressed_size, name): def __init__(self, book, book_format, uncompressed_size, name):
self.book = book self.book = book
self.format = format self.format = book_format
self.uncompressed_size = uncompressed_size self.uncompressed_size = uncompressed_size
self.name = name self.name = name
...@@ -264,7 +264,7 @@ class Books(Base): ...@@ -264,7 +264,7 @@ class Books(Base):
class Custom_Columns(Base): class Custom_Columns(Base):
__tablename__ = 'custom_columns' __tablename__ = 'custom_columns'
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
label = Column(String) label = Column(String)
name = Column(String) name = Column(String)
...@@ -274,7 +274,7 @@ class Custom_Columns(Base): ...@@ -274,7 +274,7 @@ class Custom_Columns(Base):
display = Column(String) display = Column(String)
is_multiple = Column(Boolean) is_multiple = Column(Boolean)
normalized = Column(Boolean) normalized = Column(Boolean)
def get_display_dict(self): def get_display_dict(self):
display_dict = ast.literal_eval(self.display) display_dict = ast.literal_eval(self.display)
return display_dict return display_dict
...@@ -293,7 +293,7 @@ def setup_db(): ...@@ -293,7 +293,7 @@ def setup_db():
engine = create_engine('sqlite:///'+ dbpath, echo=False, isolation_level="SERIALIZABLE") engine = create_engine('sqlite:///'+ dbpath, echo=False, isolation_level="SERIALIZABLE")
try: try:
conn = engine.connect() conn = engine.connect()
except Exception as e: except Exception:
content = ub.session.query(ub.Settings).first() content = ub.session.query(ub.Settings).first()
content.config_calibre_dir = None content.config_calibre_dir = None
content.db_configured = False content.db_configured = False
...@@ -333,15 +333,15 @@ def setup_db(): ...@@ -333,15 +333,15 @@ def setup_db():
'value': Column(String)} 'value': Column(String)}
cc_classes[row.id] = type('Custom_Column_' + str(row.id), (Base,), ccdict) cc_classes[row.id] = type('Custom_Column_' + str(row.id), (Base,), ccdict)
for id in cc_ids: for cc_id in cc_ids:
if id[1] == 'bool': if cc_id[1] == 'bool':
setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]], setattr(Books, 'custom_column_' + str(cc_id[0]), relationship(cc_classes[cc_id[0]],
primaryjoin=( primaryjoin=(
Books.id == cc_classes[id[0]].book), Books.id == cc_classes[cc_id[0]].book),
backref='books')) backref='books'))
else: else:
setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]], setattr(Books, 'custom_column_' + str(cc_id[0]), relationship(cc_classes[cc_id[0]],
secondary=books_custom_column_links[id[0]], secondary=books_custom_column_links[cc_id[0]],
backref='books')) backref='books'))
# Base.metadata.create_all(engine) # Base.metadata.create_all(engine)
......
...@@ -7,12 +7,13 @@ import os ...@@ -7,12 +7,13 @@ import os
import uploader import uploader
from iso639 import languages as isoLanguages from iso639 import languages as isoLanguages
def extractCover(zip, coverFile, coverpath, tmp_file_name):
def extractCover(zipFile, coverFile, coverpath, tmp_file_name):
if coverFile is None: if coverFile is None:
return None return None
else: else:
zipCoverPath = os.path.join(coverpath , coverFile).replace('\\','/') zipCoverPath = os.path.join(coverpath , coverFile).replace('\\','/')
cf = zip.read(zipCoverPath) cf = zipFile.read(zipCoverPath)
prefix = os.path.splitext(tmp_file_name)[0] prefix = os.path.splitext(tmp_file_name)[0]
tmp_cover_name = prefix + '.' + os.path.basename(zipCoverPath) tmp_cover_name = prefix + '.' + os.path.basename(zipCoverPath)
image = open(tmp_cover_name, 'wb') image = open(tmp_cover_name, 'wb')
...@@ -28,15 +29,15 @@ def get_epub_info(tmp_file_path, original_file_name, original_file_extension): ...@@ -28,15 +29,15 @@ def get_epub_info(tmp_file_path, original_file_name, original_file_extension):
'dc': 'http://purl.org/dc/elements/1.1/' 'dc': 'http://purl.org/dc/elements/1.1/'
} }
zip = zipfile.ZipFile(tmp_file_path) epubZip = zipfile.ZipFile(tmp_file_path)
txt = zip.read('META-INF/container.xml') txt = epubZip.read('META-INF/container.xml')
tree = etree.fromstring(txt) tree = etree.fromstring(txt)
cfname = tree.xpath('n:rootfiles/n:rootfile/@full-path', namespaces=ns)[0] cfname = tree.xpath('n:rootfiles/n:rootfile/@full-path', namespaces=ns)[0]
cf = zip.read(cfname) cf = epubZip.read(cfname)
tree = etree.fromstring(cf) tree = etree.fromstring(cf)
coverpath=os.path.dirname(cfname) coverpath = os.path.dirname(cfname)
p = tree.xpath('/pkg:package/pkg:metadata', namespaces=ns)[0] p = tree.xpath('/pkg:package/pkg:metadata', namespaces=ns)[0]
...@@ -57,7 +58,7 @@ def get_epub_info(tmp_file_path, original_file_name, original_file_extension): ...@@ -57,7 +58,7 @@ def get_epub_info(tmp_file_path, original_file_name, original_file_extension):
epub_metadata['description'] = "" epub_metadata['description'] = ""
if epub_metadata['language'] == "Unknown": if epub_metadata['language'] == "Unknown":
epub_metadata['language'] == "" epub_metadata['language'] = ""
else: else:
lang = epub_metadata['language'].split('-', 1)[0].lower() lang = epub_metadata['language'].split('-', 1)[0].lower()
if len(lang) == 2: if len(lang) == 2:
...@@ -70,24 +71,24 @@ def get_epub_info(tmp_file_path, original_file_name, original_file_extension): ...@@ -70,24 +71,24 @@ def get_epub_info(tmp_file_path, original_file_name, original_file_extension):
coversection = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='cover-image']/@href", namespaces=ns) coversection = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='cover-image']/@href", namespaces=ns)
coverfile = None coverfile = None
if len(coversection) > 0: if len(coversection) > 0:
coverfile = extractCover(zip, coversection[0], coverpath, tmp_file_path) coverfile = extractCover(epubZip, coversection[0], coverpath, tmp_file_path)
else: else:
meta_cover = tree.xpath("/pkg:package/pkg:metadata/pkg:meta[@name='cover']/@content", namespaces=ns) meta_cover = tree.xpath("/pkg:package/pkg:metadata/pkg:meta[@name='cover']/@content", namespaces=ns)
if len(meta_cover) > 0: if len(meta_cover) > 0:
coversection = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='"+meta_cover[0]+"']/@href", namespaces=ns) coversection = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='"+meta_cover[0]+"']/@href", namespaces=ns)
if len(coversection) > 0: if len(coversection) > 0:
filetype = coversection[0].rsplit('.',1)[-1] filetype = coversection[0].rsplit('.', 1)[-1]
if filetype == "xhtml" or filetype == "html": #if cover is (x)html format if filetype == "xhtml" or filetype == "html": #if cover is (x)html format
markup = zip.read(os.path.join(coverpath,coversection[0])) markup = epubZip.read(os.path.join(coverpath, coversection[0]))
markupTree = etree.fromstring(markup) markupTree = etree.fromstring(markup)
#no matter xhtml or html with no namespace # no matter xhtml or html with no namespace
imgsrc = markupTree.xpath("//*[local-name() = 'img']/@src") imgsrc = markupTree.xpath("//*[local-name() = 'img']/@src")
#imgsrc maybe startwith "../"" so fullpath join then relpath to cwd # imgsrc maybe startwith "../"" so fullpath join then relpath to cwd
filename = os.path.relpath(os.path.join(os.path.dirname(os.path.join(coverpath, coversection[0])), imgsrc[0])) filename = os.path.relpath(os.path.join(os.path.dirname(os.path.join(coverpath, coversection[0])), imgsrc[0]))
coverfile = extractCover(zip, filename, "", tmp_file_path) coverfile = extractCover(epubZip, filename, "", tmp_file_path)
else: else:
coverfile = extractCover(zip, coversection[0], coverpath, tmp_file_path) coverfile = extractCover(epubZip, coversection[0], coverpath, tmp_file_path)
if epub_metadata['title'] is None: if epub_metadata['title'] is None:
title = original_file_name title = original_file_name
else: else:
......
...@@ -2,12 +2,11 @@ ...@@ -2,12 +2,11 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from lxml import etree from lxml import etree
import os
import uploader import uploader
try: #try:
from io import StringIO # from io import StringIO
except ImportError as e: #except ImportError:
import StringIO # import StringIO
def get_fb2_info(tmp_file_path, original_file_extension): def get_fb2_info(tmp_file_path, original_file_extension):
......
...@@ -4,12 +4,11 @@ try: ...@@ -4,12 +4,11 @@ try:
from apiclient import errors from apiclient import errors
except ImportError: except ImportError:
pass pass
import os, time import os
from ub import config from ub import config
from sqlalchemy import * from sqlalchemy import *
from sqlalchemy import exc
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import * from sqlalchemy.orm import *
...@@ -104,7 +103,7 @@ def getEbooksFolderId(drive=None): ...@@ -104,7 +103,7 @@ def getEbooksFolderId(drive=None):
gDriveId.path='/' gDriveId.path='/'
session.merge(gDriveId) session.merge(gDriveId)
session.commit() session.commit()
return return
def getFolderInFolder(parentId, folderName, drive=None): def getFolderInFolder(parentId, folderName, drive=None):
if not drive: if not drive:
...@@ -113,7 +112,7 @@ def getFolderInFolder(parentId, folderName, drive=None): ...@@ -113,7 +112,7 @@ def getFolderInFolder(parentId, folderName, drive=None):
drive.auth.Refresh() drive.auth.Refresh()
folder= "title = '%s' and '%s' in parents and mimeType = 'application/vnd.google-apps.folder' and trashed = false" % (folderName.replace("'", "\\'"), parentId) folder= "title = '%s' and '%s' in parents and mimeType = 'application/vnd.google-apps.folder' and trashed = false" % (folderName.replace("'", "\\'"), parentId)
fileList = drive.ListFile({'q': folder}).GetList() fileList = drive.ListFile({'q': folder}).GetList()
return fileList[0] return fileList[0]
def getFile(pathId, fileName, drive=None): def getFile(pathId, fileName, drive=None):
if not drive: if not drive:
...@@ -165,11 +164,11 @@ def getFileFromEbooksFolder(drive, path, fileName): ...@@ -165,11 +164,11 @@ def getFileFromEbooksFolder(drive, path, fileName):
if drive.auth.access_token_expired: if drive.auth.access_token_expired:
drive.auth.Refresh() drive.auth.Refresh()
if path: if path:
sqlCheckPath=path if path[-1] =='/' else path + '/' # sqlCheckPath=path if path[-1] =='/' else path + '/'
folderId=getFolderId(path, drive) folderId=getFolderId(path, drive)
else: else:
folderId=getEbooksFolderId(drive) folderId=getEbooksFolderId(drive)
return getFile(folderId, fileName, drive) return getFile(folderId, fileName, drive)
def copyDriveFileRemote(drive, origin_file_id, copy_title): def copyDriveFileRemote(drive, origin_file_id, copy_title):
...@@ -195,7 +194,6 @@ def downloadFile(drive, path, filename, output): ...@@ -195,7 +194,6 @@ def downloadFile(drive, path, filename, output):
f.GetContentFile(output) f.GetContentFile(output)
def backupCalibreDbAndOptionalDownload(drive, f=None): def backupCalibreDbAndOptionalDownload(drive, f=None):
pass
if not drive: if not drive:
drive=getDrive() drive=getDrive()
if drive.auth.access_token_expired: if drive.auth.access_token_expired:
...@@ -203,15 +201,16 @@ def backupCalibreDbAndOptionalDownload(drive, f=None): ...@@ -203,15 +201,16 @@ def backupCalibreDbAndOptionalDownload(drive, f=None):
metaDataFile="'%s' in parents and title = 'metadata.db' and trashed = false" % getEbooksFolderId() metaDataFile="'%s' in parents and title = 'metadata.db' and trashed = false" % getEbooksFolderId()
fileList = drive.ListFile({'q': metaDataFile}).GetList() fileList = drive.ListFile({'q': metaDataFile}).GetList()
databaseFile=fileList[0] databaseFile=fileList[0]
if f: if f:
databaseFile.GetContentFile(f) databaseFile.GetContentFile(f)
def copyToDrive(drive, uploadFile, createRoot, replaceFiles, def copyToDrive(drive, uploadFile, createRoot, replaceFiles,
ignoreFiles=[], ignoreFiles=[],
parent=None, prevDir=''): parent=None, prevDir=''):
if not drive: if not drive:
drive=getDrive() drive=getDrive()
if drive.auth.access_token_expired: if drive.auth.access_token_expired:
...@@ -222,7 +221,7 @@ def copyToDrive(drive, uploadFile, createRoot, replaceFiles, ...@@ -222,7 +221,7 @@ def copyToDrive(drive, uploadFile, createRoot, replaceFiles,
if os.path.isdir(os.path.join(prevDir,uploadFile)): if os.path.isdir(os.path.join(prevDir,uploadFile)):
existingFolder=drive.ListFile({'q' : "title = '%s' and '%s' in parents and trashed = false" % (os.path.basename(uploadFile), parent['id'])}).GetList() existingFolder=drive.ListFile({'q' : "title = '%s' and '%s' in parents and trashed = false" % (os.path.basename(uploadFile), parent['id'])}).GetList()
if len(existingFolder) == 0 and (not isInitial or createRoot): if len(existingFolder) == 0 and (not isInitial or createRoot):
parent = drive.CreateFile({'title': os.path.basename(uploadFile), 'parents' : [{"kind": "drive#fileLink", 'id' : parent['id']}], parent = drive.CreateFile({'title': os.path.basename(uploadFile), 'parents' : [{"kind": "drive#fileLink", 'id' : parent['id']}],
"mimeType": "application/vnd.google-apps.folder" }) "mimeType": "application/vnd.google-apps.folder" })
parent.Upload() parent.Upload()
else: else:
...@@ -260,7 +259,7 @@ def uploadFileToEbooksFolder(drive, destFile, f): ...@@ -260,7 +259,7 @@ def uploadFileToEbooksFolder(drive, destFile, f):
else: else:
existingFolder=drive.ListFile({'q' : "title = '%s' and '%s' in parents and trashed = false" % (x, parent['id'])}).GetList() existingFolder=drive.ListFile({'q' : "title = '%s' and '%s' in parents and trashed = false" % (x, parent['id'])}).GetList()
if len(existingFolder) == 0: if len(existingFolder) == 0:
parent = drive.CreateFile({'title': x, 'parents' : [{"kind": "drive#fileLink", 'id' : parent['id']}], parent = drive.CreateFile({'title': x, 'parents' : [{"kind": "drive#fileLink", 'id' : parent['id']}],
"mimeType": "application/vnd.google-apps.folder" }) "mimeType": "application/vnd.google-apps.folder" })
parent.Upload() parent.Upload()
else: else:
...@@ -273,20 +272,19 @@ def watchChange(drive, channel_id, channel_type, channel_address, ...@@ -273,20 +272,19 @@ def watchChange(drive, channel_id, channel_type, channel_address,
drive=getDrive() drive=getDrive()
if drive.auth.access_token_expired: if drive.auth.access_token_expired:
drive.auth.Refresh() drive.auth.Refresh()
"""Watch for all changes to a user's Drive. # Watch for all changes to a user's Drive.
Args: # Args:
service: Drive API service instance. # service: Drive API service instance.
channel_id: Unique string that identifies this channel. # channel_id: Unique string that identifies this channel.
channel_type: Type of delivery mechanism used for this channel. # channel_type: Type of delivery mechanism used for this channel.
channel_address: Address where notifications are delivered. # channel_address: Address where notifications are delivered.
channel_token: An arbitrary string delivered to the target address with # channel_token: An arbitrary string delivered to the target address with
each notification delivered over this channel. Optional. # each notification delivered over this channel. Optional.
channel_address: Address where notifications are delivered. Optional. # channel_address: Address where notifications are delivered. Optional.
Returns: # Returns:
The created channel if successful # The created channel if successful
Raises: # Raises:
apiclient.errors.HttpError: if http request to create channel fails. # apiclient.errors.HttpError: if http request to create channel fails.
"""
body = { body = {
'id': channel_id, 'id': channel_id,
'type': channel_type, 'type': channel_type,
...@@ -343,8 +341,8 @@ def stopChannel(drive, channel_id, resource_id): ...@@ -343,8 +341,8 @@ def stopChannel(drive, channel_id, resource_id):
if not drive: if not drive:
drive=getDrive() drive=getDrive()
if drive.auth.access_token_expired: if drive.auth.access_token_expired:
drive.auth.Refresh() drive.auth.Refresh()
service=drive.auth.service # service=drive.auth.service
body = { body = {
'id': channel_id, 'id': channel_id,
'resourceId': resource_id 'resourceId': resource_id
...@@ -355,16 +353,15 @@ def getChangeById (drive, change_id): ...@@ -355,16 +353,15 @@ def getChangeById (drive, change_id):
if not drive: if not drive:
drive=getDrive() drive=getDrive()
if drive.auth.access_token_expired: if drive.auth.access_token_expired:
drive.auth.Refresh() drive.auth.Refresh()
"""Print a single Change resource information. # Print a single Change resource information.
#
Args: # Args:
service: Drive API service instance. # service: Drive API service instance.
change_id: ID of the Change resource to retrieve. # change_id: ID of the Change resource to retrieve.
"""
try: try:
change = drive.auth.service.changes().get(changeId=change_id).execute() change = drive.auth.service.changes().get(changeId=change_id).execute()
return change return change
except errors.HttpError, error: except (errors.HttpError, error):
web.app.logger.exception(error) web.app.logger.exception(error)
return None return None
...@@ -13,6 +13,7 @@ import os ...@@ -13,6 +13,7 @@ import os
import traceback import traceback
import re import re
import unicodedata import unicodedata
try: try:
from StringIO import StringIO from StringIO import StringIO
from email.MIMEBase import MIMEBase from email.MIMEBase import MIMEBase
...@@ -43,9 +44,9 @@ import web ...@@ -43,9 +44,9 @@ import web
try: try:
import unidecode import unidecode
use_unidecode=True use_unidecode = True
except Exception as e: except Exception as e:
use_unidecode=False use_unidecode = False
# Global variables # Global variables
global_task = None global_task = None
...@@ -80,7 +81,7 @@ def make_mobi(book_id, calibrepath): ...@@ -80,7 +81,7 @@ def make_mobi(book_id, calibrepath):
file_path = os.path.join(calibrepath, book.path, data.name) file_path = os.path.join(calibrepath, book.path, data.name)
if os.path.exists(file_path + u".epub"): if os.path.exists(file_path + u".epub"):
p = subprocess.Popen((kindlegen + " \"" + file_path + u".epub\" ").encode(sys.getfilesystemencoding()), p = subprocess.Popen((kindlegen + " \"" + file_path + u".epub\" ").encode(sys.getfilesystemencoding()),
shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# Poll process for new output until finished # Poll process for new output until finished
while True: while True:
nextline = p.stdout.readline() nextline = p.stdout.readline()
...@@ -93,7 +94,7 @@ def make_mobi(book_id, calibrepath): ...@@ -93,7 +94,7 @@ def make_mobi(book_id, calibrepath):
if not check or check < 2: if not check or check < 2:
book.data.append(db.Data( book.data.append(db.Data(
name=book.data[0].name, name=book.data[0].name,
format="MOBI", book_format="MOBI",
book=book.id, book=book.id,
uncompressed_size=os.path.getsize(file_path + ".mobi") uncompressed_size=os.path.getsize(file_path + ".mobi")
)) ))
...@@ -242,7 +243,7 @@ def get_valid_filename(value, replace_whitespace=True): ...@@ -242,7 +243,7 @@ def get_valid_filename(value, replace_whitespace=True):
Returns the given string converted to a string that can be used for a clean Returns the given string converted to a string that can be used for a clean
filename. Limits num characters to 128 max. filename. Limits num characters to 128 max.
""" """
if value[-1:] ==u'.': if value[-1:] == u'.':
value = value[:-1]+u'_' value = value[:-1]+u'_'
if use_unidecode: if use_unidecode:
value=(unidecode.unidecode(value)).strip() value=(unidecode.unidecode(value)).strip()
...@@ -251,7 +252,7 @@ def get_valid_filename(value, replace_whitespace=True): ...@@ -251,7 +252,7 @@ def get_valid_filename(value, replace_whitespace=True):
value=value.replace(u'ß',u'ss') value=value.replace(u'ß',u'ss')
value = unicodedata.normalize('NFKD', value) value = unicodedata.normalize('NFKD', value)
re_slugify = re.compile('[\W\s-]', re.UNICODE) re_slugify = re.compile('[\W\s-]', re.UNICODE)
if type(value) is str: #Python3 str, Python2 unicode if isinstance(value, str): #Python3 str, Python2 unicode
value = re_slugify.sub('', value).strip() value = re_slugify.sub('', value).strip()
else: else:
value = unicode(re_slugify.sub('', value).strip()) value = unicode(re_slugify.sub('', value).strip())
...@@ -266,7 +267,7 @@ def get_sorted_author(value): ...@@ -266,7 +267,7 @@ def get_sorted_author(value):
regexes = ["^(JR|SR)\.?$","^I{1,3}\.?$","^IV\.?$"] regexes = ["^(JR|SR)\.?$","^I{1,3}\.?$","^IV\.?$"]
combined = "(" + ")|(".join(regexes) + ")" combined = "(" + ")|(".join(regexes) + ")"
value = value.split(" ") value = value.split(" ")
if re.match(combined,value[-1].upper()): if re.match(combined, value[-1].upper()):
value2 = value[-2] + ", " + " ".join(value[:-2]) + " " + value[-1] value2 = value[-2] + ", " + " ".join(value[:-2]) + " " + value[-1]
else: else:
value2 = value[-1] + ", " + " ".join(value[:-1]) value2 = value[-1] + ", " + " ".join(value[:-1])
...@@ -277,28 +278,29 @@ def update_dir_stucture(book_id, calibrepath): ...@@ -277,28 +278,29 @@ def update_dir_stucture(book_id, calibrepath):
db.session.connection().connection.connection.create_function("title_sort", 1, db.title_sort) db.session.connection().connection.connection.create_function("title_sort", 1, db.title_sort)
book = db.session.query(db.Books).filter(db.Books.id == book_id).first() book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
path = os.path.join(calibrepath, book.path)#.replace('/',os.path.sep)).replace('\\',os.path.sep) path = os.path.join(calibrepath, book.path)#.replace('/',os.path.sep)).replace('\\',os.path.sep)
authordir = book.path.split('/')[0] authordir = book.path.split('/')[0]
new_authordir = get_valid_filename(book.authors[0].name) new_authordir = get_valid_filename(book.authors[0].name)
titledir = book.path.split('/')[1] titledir = book.path.split('/')[1]
new_titledir = get_valid_filename(book.title) + " (" + str(book_id) + ")" new_titledir = get_valid_filename(book.title) + " (" + str(book_id) + ")"
if titledir != new_titledir: if titledir != new_titledir:
new_title_path = os.path.join(os.path.dirname(path), new_titledir) new_title_path = os.path.join(os.path.dirname(path), new_titledir)
os.rename(path, new_title_path) os.rename(path, new_title_path)
path = new_title_path path = new_title_path
book.path = book.path.split('/')[0] + '/' + new_titledir book.path = book.path.split('/')[0] + '/' + new_titledir
if authordir != new_authordir: if authordir != new_authordir:
new_author_path = os.path.join(os.path.join(calibrepath, new_authordir), os.path.basename(path)) new_author_path = os.path.join(os.path.join(calibrepath, new_authordir), os.path.basename(path))
os.renames(path, new_author_path) os.renames(path, new_author_path)
book.path = new_authordir + '/' + book.path.split('/')[1] book.path = new_authordir + '/' + book.path.split('/')[1]
db.session.commit() db.session.commit()
def update_dir_structure_gdrive(book_id): def update_dir_structure_gdrive(book_id):
db.session.connection().connection.connection.create_function("title_sort", 1, db.title_sort) db.session.connection().connection.connection.create_function("title_sort", 1, db.title_sort)
book = db.session.query(db.Books).filter(db.Books.id == book_id).first() book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
authordir = book.path.split('/')[0] authordir = book.path.split('/')[0]
new_authordir = get_valid_filename(book.authors[0].name) new_authordir = get_valid_filename(book.authors[0].name)
titledir = book.path.split('/')[1] titledir = book.path.split('/')[1]
...@@ -313,7 +315,7 @@ def update_dir_structure_gdrive(book_id): ...@@ -313,7 +315,7 @@ def update_dir_structure_gdrive(book_id):
if authordir != new_authordir: if authordir != new_authordir:
gFile=gd.getFileFromEbooksFolder(web.Gdrive.Instance().drive,None,authordir) gFile=gd.getFileFromEbooksFolder(web.Gdrive.Instance().drive,None,authordir)
gFile['title']= new_authordir gFile['title'] = new_authordir
gFile.Upload() gFile.Upload()
book.path = new_authordir + '/' + book.path.split('/')[1] book.path = new_authordir + '/' + book.path.split('/')[1]
...@@ -327,41 +329,44 @@ class Updater(threading.Thread): ...@@ -327,41 +329,44 @@ class Updater(threading.Thread):
def run(self): def run(self):
global global_task global global_task
self.status=1 self.status = 1
r = requests.get('https://api.github.com/repos/janeczku/calibre-web/zipball/master', stream=True) r = requests.get('https://api.github.com/repos/janeczku/calibre-web/zipball/master', stream=True)
fname = re.findall("filename=(.+)", r.headers['content-disposition'])[0] fname = re.findall("filename=(.+)", r.headers['content-disposition'])[0]
self.status=2 self.status = 2
z = zipfile.ZipFile(StringIO(r.content)) z = zipfile.ZipFile(StringIO(r.content))
self.status=3 self.status = 3
tmp_dir = gettempdir() tmp_dir = gettempdir()
z.extractall(tmp_dir) z.extractall(tmp_dir)
self.status=4 self.status = 4
self.update_source(os.path.join(tmp_dir,os.path.splitext(fname)[0]),ub.config.get_main_dir) self.update_source(os.path.join(tmp_dir,os.path.splitext(fname)[0]),ub.config.get_main_dir)
self.status=5 self.status = 5
global_task = 0 global_task = 0
db.session.close() db.session.close()
db.engine.dispose() db.engine.dispose()
ub.session.close() ub.session.close()
ub.engine.dispose() ub.engine.dispose()
self.status=6 self.status = 6
if web.gevent_server: if web.gevent_server:
web.gevent_server.stop() web.gevent_server.stop()
else: else:
# stop tornado server # stop tornado server
server = IOLoop.instance() server = IOLoop.instance()
server.add_callback(server.stop) server.add_callback(server.stop)
self.status=7 self.status = 7
def get_update_status(self): def get_update_status(self):
return self.status return self.status
@classmethod
def file_to_list(self, file): def file_to_list(self, file):
return [x.strip() for x in open(file, 'r') if not x.startswith('#EXT')] return [x.strip() for x in open(file, 'r') if not x.startswith('#EXT')]
@classmethod
def one_minus_two(self, one, two): def one_minus_two(self, one, two):
return [x for x in one if x not in set(two)] return [x for x in one if x not in set(two)]
@classmethod
def reduce_dirs(self, delete_files, new_list): def reduce_dirs(self, delete_files, new_list):
new_delete = [] new_delete = []
for file in delete_files: for file in delete_files:
...@@ -382,6 +387,7 @@ class Updater(threading.Thread): ...@@ -382,6 +387,7 @@ class Updater(threading.Thread):
break break
return list(set(new_delete)) return list(set(new_delete))
@classmethod
def reduce_files(self, remove_items, exclude_items): def reduce_files(self, remove_items, exclude_items):
rf = [] rf = []
for item in remove_items: for item in remove_items:
...@@ -389,6 +395,7 @@ class Updater(threading.Thread): ...@@ -389,6 +395,7 @@ class Updater(threading.Thread):
rf.append(item) rf.append(item)
return rf return rf
@classmethod
def moveallfiles(self, root_src_dir, root_dst_dir): def moveallfiles(self, root_src_dir, root_dst_dir):
change_permissions = True change_permissions = True
if sys.platform == "win32" or sys.platform == "darwin": if sys.platform == "win32" or sys.platform == "darwin":
...@@ -431,8 +438,8 @@ class Updater(threading.Thread): ...@@ -431,8 +438,8 @@ class Updater(threading.Thread):
# destination files # destination files
old_list = list() old_list = list()
exclude = ( exclude = (
'vendor' + os.sep + 'kindlegen.exe', 'vendor' + os.sep + 'kindlegen', os.sep + 'app.db', 'vendor' + os.sep + 'kindlegen.exe', 'vendor' + os.sep + 'kindlegen', os.sep + 'app.db',
os.sep + 'vendor',os.sep + 'calibre-web.log') os.sep + 'vendor', os.sep + 'calibre-web.log')
for root, dirs, files in os.walk(destination, topdown=True): for root, dirs, files in os.walk(destination, topdown=True):
for name in files: for name in files:
old_list.append(os.path.join(root, name).replace(destination, '')) old_list.append(os.path.join(root, name).replace(destination, ''))
...@@ -462,9 +469,9 @@ class Updater(threading.Thread): ...@@ -462,9 +469,9 @@ class Updater(threading.Thread):
else: else:
try: try:
logging.getLogger('cps.web').debug("Delete file " + item_path) logging.getLogger('cps.web').debug("Delete file " + item_path)
log_from_thread("Delete file " + item_path) # log_from_thread("Delete file " + item_path)
os.remove(item_path) os.remove(item_path)
except Exception as e: except Exception:
logging.getLogger('cps.web').debug("Could not remove:" + item_path) logging.getLogger('cps.web').debug("Could not remove:" + item_path)
shutil.rmtree(source, ignore_errors=True) shutil.rmtree(source, ignore_errors=True)
/** /**
* Created by SpeedProg on 05.04.2015. * Created by SpeedProg on 05.04.2015.
*/ */
/* global Bloodhound */
/* /*
Takes a prefix, query typeahead callback, Bloodhound typeahead adapter Takes a prefix, query typeahead callback, Bloodhound typeahead adapter
and returns the completions it gets from the bloodhound engine prefixed. and returns the completions it gets from the bloodhound engine prefixed.
*/ */
function prefixed_source(prefix, query, cb, bh_adapter) { function prefixedSource(prefix, query, cb, bhAdapter) {
bh_adapter(query, function(retArray){ bhAdapter(query, function(retArray){
var matches = []; var matches = [];
for (var i = 0; i < retArray.length; i++) { for (var i = 0; i < retArray.length; i++) {
var obj = {name : prefix + retArray[i].name}; var obj = {name : prefix + retArray[i].name};
...@@ -16,184 +18,161 @@ function prefixed_source(prefix, query, cb, bh_adapter) { ...@@ -16,184 +18,161 @@ function prefixed_source(prefix, query, cb, bh_adapter) {
cb(matches); cb(matches);
}); });
} }
function get_path(){ function getPath(){
var jsFileLocation = $('script[src*=edit_books]').attr('src'); // the js file path var jsFileLocation = $("script[src*=edit_books]").attr("src"); // the js file path
jsFileLocation = jsFileLocation.replace('/static/js/edit_books.js', ''); // the js folder path jsFileLocation = jsFileLocation.replace("/static/js/edit_books.js", ""); // the js folder path
return jsFileLocation; return jsFileLocation;
} }
var authors = new Bloodhound({ var authors = new Bloodhound({
name: 'authors', name: "authors",
datumTokenizer: function(datum) { datumTokenizer(datum) {
return [datum.name]; return [datum.name];
}, },
queryTokenizer: Bloodhound.tokenizers.whitespace, queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: { remote: {
url: get_path()+'/get_authors_json?q=%QUERY' url: getPath()+"/get_authors_json?q=%QUERY"
} }
}); });
function authors_source(query, cb) {
var bh_adapter = authors.ttAdapter();
var tokens = query.split("&");
var current_author = tokens[tokens.length-1].trim();
tokens.splice(tokens.length-1, 1); // remove last element
var prefix = "";
for (var i = 0; i < tokens.length; i++) {
var author = tokens[i].trim();
prefix += author + " & ";
}
prefixed_source(prefix, current_author, cb, bh_adapter);
}
var promise = authors.initialize();
promise.done(function(){
$("#bookAuthor").typeahead(
{
highlight: true, minLength: 1,
hint: true
}, {
name: 'authors', displayKey: 'name',
source: authors_source
}
)
});
var series = new Bloodhound({ var series = new Bloodhound({
name: 'series', name: "series",
datumTokenizer: function(datum) { datumTokenizer(datum) {
return [datum.name]; return [datum.name];
}, },
queryTokenizer: function(query) { queryTokenizer(query) {
return [query]; return [query];
}, },
remote: { remote: {
url: get_path()+'/get_series_json?q=', url: getPath()+"/get_series_json?q=",
replace: function(url, query) { replace(url, query) {
url_query = url+encodeURIComponent(query); return url+encodeURIComponent(query);
return url_query;
} }
} }
}); });
var promise = series.initialize();
promise.done(function(){
$("#series").typeahead(
{
highlight: true, minLength: 0,
hint: true
}, {
name: 'series', displayKey: 'name',
source: series.ttAdapter()
}
)
});
var tags = new Bloodhound({ var tags = new Bloodhound({
name: 'tags', name: "tags",
datumTokenizer: function(datum) { datumTokenizer(datum) {
return [datum.name]; return [datum.name];
}, },
queryTokenizer: function(query) { queryTokenizer(query) {
tokens = query.split(","); var tokens = query.split(",");
tokens = [tokens[tokens.length-1].trim()]; tokens = [tokens[tokens.length-1].trim()];
return tokens return tokens;
}, },
remote: { remote: {
url: get_path()+'/get_tags_json?q=%QUERY' url: getPath()+"/get_tags_json?q=%QUERY"
}
});
function tag_source(query, cb) {
var bh_adapter = tags.ttAdapter();
var tokens = query.split(",");
var current_tag = tokens[tokens.length-1].trim();
tokens.splice(tokens.length-1, 1); // remove last element
var prefix = "";
for (var i = 0; i < tokens.length; i++) {
var tag = tokens[i].trim();
prefix += tag + ", ";
} }
prefixed_source(prefix, current_tag, cb, bh_adapter);
}
var promise = tags.initialize();
promise.done(function(){
$("#tags").typeahead(
{
highlight: true, minLength: 0,
hint: true
}, {
name: 'tags', displayKey: 'name',
source: tag_source
}
)
}); });
var languages = new Bloodhound({ var languages = new Bloodhound({
name: 'languages', name: "languages",
datumTokenizer: function(datum) { datumTokenizer(datum) {
return [datum.name]; return [datum.name];
}, },
queryTokenizer: function(query) { queryTokenizer(query) {
return [query]; return [query];
}, },
remote: { remote: {
url: get_path()+'/get_languages_json?q=', url: getPath()+"/get_languages_json?q=",
replace: function(url, query) { replace(url, query) {
url_query = url+encodeURIComponent(query); return url+encodeURIComponent(query);
return url_query;
} }
} }
}); });
function language_source(query, cb) { function sourceSplit(query, cb, split, source) {
var bh_adapter = languages.ttAdapter(); var bhAdapter = source.ttAdapter();
var tokens = query.split(","); var tokens = query.split(split);
var current_language = tokens[tokens.length-1].trim(); var currentSource = tokens[tokens.length-1].trim();
tokens.splice(tokens.length-1, 1); // remove last element tokens.splice(tokens.length-1, 1); // remove last element
var prefix = ""; var prefix = "";
var newSplit;
if (split === "&"){
newSplit = " " + split + " ";
}else{
newSplit = split + " ";
}
for (var i = 0; i < tokens.length; i++) { for (var i = 0; i < tokens.length; i++) {
var tag = tokens[i].trim(); prefix += tokens[i].trim() + newSplit;
prefix += tag + ", ";
} }
prefixedSource(prefix, currentSource, cb, bhAdapter);
prefixed_source(prefix, current_language, cb, bh_adapter);
} }
var promise = languages.initialize(); var promiseAuthors = authors.initialize();
promise.done(function(){ promiseAuthors.done(function(){
$("#languages").typeahead( $("#bookAuthor").typeahead(
{
highlight: true, minLength: 1,
hint: true
}, {
name: "authors",
displayKey: "name",
source(query, cb){
return sourceSplit(query, cb, "&", authors); //sourceSplit //("&")
}
});
});
var promiseSeries = series.initialize();
promiseSeries.done(function(){
$("#series").typeahead(
{ {
highlight: true, minLength: 0, highlight: true, minLength: 0,
hint: true hint: true
}, { }, {
name: 'languages', displayKey: 'name', name: "series",
source: language_source displayKey: "name",
source: series.ttAdapter()
} }
) );
}); });
$('form').on('change input typeahead:selected', function(data){ var promiseTags = tags.initialize();
form = $('form').serialize(); promiseTags.done(function(){
$.getJSON( get_path()+"/get_matching_tags", form, function( data ) { $("#tags").typeahead(
$('.tags_click').each(function() { {
if ($.inArray(parseInt($(this).children('input').first().val(), 10), data.tags) == -1 ) { highlight: true, minLength: 0,
if (!($(this).hasClass('active'))) { hint: true
$(this).addClass('disabled'); }, {
name: "tags",
displayKey: "name",
source(query, cb){
return sourceSplit(query, cb, ",", tags);
}
});
});
var promiseLanguages = languages.initialize();
promiseLanguages.done(function(){
$("#languages").typeahead(
{
highlight: true, minLength: 0,
hint: true
}, {
name: "languages",
displayKey: "name",
source(query, cb){
return sourceSplit(query, cb, ",", languages); //(",")
}
});
});
$("form").on("change input typeahead:selected", function(data){
var form = $("form").serialize();
$.getJSON( getPath()+"/get_matching_tags", form, function( data ) {
$(".tags_click").each(function() {
if ($.inArray(parseInt($(this).children("input").first().val(), 10), data.tags) === -1 ) {
if (!($(this).hasClass("active"))) {
$(this).addClass("disabled");
} }
} }
else { else {
$(this).removeClass('disabled'); $(this).removeClass("disabled");
} }
}); });
}); });
......
This diff is collapsed.
...@@ -3,13 +3,47 @@ var updateTimerID; ...@@ -3,13 +3,47 @@ var updateTimerID;
var updateText; var updateText;
$(function() { $(function() {
$('.discover .row').isotope({
function restartTimer() {
$("#spinner").addClass("hidden");
$("#RestartDialog").modal("hide");
}
function updateTimer() {
$.ajax({
dataType: "json",
url: window.location.pathname+"/../../get_updater_status",
success(data) {
// console.log(data.status);
$("#UpdateprogressDialog #Updatecontent").html(updateText[data.status]);
if (data.status >6){
clearInterval(updateTimerID);
$("#spinner2").hide();
$("#UpdateprogressDialog #updateFinished").removeClass("hidden");
$("#check_for_update").removeClass("hidden");
$("#perform_update").addClass("hidden");
}
},
error() {
// console.log('Done');
clearInterval(updateTimerID);
$("#spinner2").hide();
$("#UpdateprogressDialog #Updatecontent").html(updateText[7]);
$("#UpdateprogressDialog #updateFinished").removeClass("hidden");
$("#check_for_update").removeClass("hidden");
$("#perform_update").addClass("hidden");
},
timeout:2000
});
}
$(".discover .row").isotope({
// options // options
itemSelector : '.book', itemSelector : ".book",
layoutMode : 'fitRows' layoutMode : "fitRows"
}); });
$('.load-more .row').infinitescroll({ $(".load-more .row").infinitescroll({
debug: false, debug: false,
navSelector : ".pagination", navSelector : ".pagination",
// selector for the paged navigation (it will be hidden) // selector for the paged navigation (it will be hidden)
...@@ -20,109 +54,74 @@ $(function() { ...@@ -20,109 +54,74 @@ $(function() {
extraScrollPx: 300, extraScrollPx: 300,
// selector for all items you'll retrieve // selector for all items you'll retrieve
}, function(data){ }, function(data){
$('.load-more .row').isotope( 'appended', $(data), null ); $(".load-more .row").isotope( "appended", $(data), null );
}); });
$('#sendbtn').click(function(){ $("#sendbtn").click(function(){
var $this = $(this); var $this = $(this);
$this.text('Please wait...'); $this.text("Please wait...");
$this.addClass('disabled'); $this.addClass("disabled");
}); });
$("#restart").click(function() { $("#restart").click(function() {
$.ajax({ $.ajax({
dataType: 'json', dataType: "json",
url: window.location.pathname+"/../../shutdown", url: window.location.pathname+"/../../shutdown",
data: {"parameter":0}, data: {"parameter":0},
success: function(data) { success(data) {
$('#spinner').show(); $("#spinner").show();
displaytext=data.text; displaytext=data.text;
setTimeout(restartTimer, 3000);} setTimeout(restartTimer, 3000);}
}); });
}); });
$("#shutdown").click(function() { $("#shutdown").click(function() {
$.ajax({ $.ajax({
dataType: 'json', dataType: "json",
url: window.location.pathname+"/../../shutdown", url: window.location.pathname+"/../../shutdown",
data: {"parameter":1}, data: {"parameter":1},
success: function(data) { success(data) {
return alert(data.text);} return alert(data.text);}
}); });
}); });
$("#check_for_update").click(function() { $("#check_for_update").click(function() {
var button_text = $("#check_for_update").html(); var buttonText = $("#check_for_update").html();
$("#check_for_update").html('...'); $("#check_for_update").html("...");
$.ajax({ $.ajax({
dataType: 'json', dataType: "json",
url: window.location.pathname+"/../../get_update_status", url: window.location.pathname+"/../../get_update_status",
success: function(data) { success(data) {
$("#check_for_update").html(button_text); $("#check_for_update").html(buttonText);
if (data.status == true) { if (data.status === true) {
$("#check_for_update").addClass('hidden'); $("#check_for_update").addClass("hidden");
$("#perform_update").removeClass('hidden'); $("#perform_update").removeClass("hidden");
$("#update_info").removeClass('hidden'); $("#update_info").removeClass("hidden");
$("#update_info").find('span').html(data.commit); $("#update_info").find("span").html(data.commit);
} }
} }
}); });
}); });
$("#restart_database").click(function() { $("#restart_database").click(function() {
$.ajax({ $.ajax({
dataType: 'json', dataType: "json",
url: window.location.pathname+"/../../shutdown", url: window.location.pathname+"/../../shutdown",
data: {"parameter":2} data: {"parameter":2}
}); });
}); });
$("#perform_update").click(function() { $("#perform_update").click(function() {
$('#spinner2').show(); $("#spinner2").show();
$.ajax({ $.ajax({
type: "POST", type: "POST",
dataType: 'json', dataType: "json",
data: { start: "True"}, data: { start: "True"},
url: window.location.pathname+"/../../get_updater_status", url: window.location.pathname+"/../../get_updater_status",
success: function(data) { success(data) {
updateText=data.text updateText=data.text;
$("#UpdateprogressDialog #Updatecontent").html(updateText[data.status]); $("#UpdateprogressDialog #Updatecontent").html(updateText[data.status]);
console.log(data.status); // console.log(data.status);
updateTimerID=setInterval(updateTimer, 2000);} updateTimerID=setInterval(updateTimer, 2000);}
}); });
}); });
});
function restartTimer() {
$('#spinner').hide();
$('#RestartDialog').modal('hide');
}
function updateTimer() { $(window).resize(function(event) {
$.ajax({ $(".discover .row").isotope("reLayout");
dataType: 'json',
url: window.location.pathname+"/../../get_updater_status",
success: function(data) {
console.log(data.status);
$("#UpdateprogressDialog #Updatecontent").html(updateText[data.status]);
if (data.status >6){
clearInterval(updateTimerID);
$('#spinner2').hide();
$('#UpdateprogressDialog #updateFinished').removeClass('hidden');
$("#check_for_update").removeClass('hidden');
$("#perform_update").addClass('hidden');
}
},
error: function() {
console.log('Done');
clearInterval(updateTimerID);
$('#spinner2').hide();
$("#UpdateprogressDialog #Updatecontent").html(updateText[7]);
$('#UpdateprogressDialog #updateFinished').removeClass('hidden');
$("#check_for_update").removeClass('hidden');
$("#perform_update").addClass('hidden');
},
timeout:2000
}); });
} });
\ No newline at end of file
$(window).resize(function(event) {
$('.discover .row').isotope('reLayout');
});
Sortable.create(sortTrue, { /* global Sortable,sortTrue */
var sortable = Sortable.create(sortTrue, {
group: "sorting", group: "sorting",
sort: true sort: true
}); });
...@@ -9,7 +11,7 @@ function sendData(path){ ...@@ -9,7 +11,7 @@ function sendData(path){
var maxElements; var maxElements;
var tmp=[]; var tmp=[];
elements=Sortable.utils.find(sortTrue,"div"); elements=sortable.utils.find(sortTrue,"div");
maxElements=elements.length; maxElements=elements.length;
var form = document.createElement("form"); var form = document.createElement("form");
......
...@@ -106,7 +106,7 @@ ...@@ -106,7 +106,7 @@
</div> </div>
<a href="#" id="get_meta" class="btn btn-default" data-toggle="modal" data-target="#metaModal">{{_('Get metadata')}}</a> <a href="#" id="get_meta" class="btn btn-default" data-toggle="modal" data-target="#metaModal">{{_('Get metadata')}}</a>
<button type="submit" class="btn btn-default">{{_('Submit')}}</button> <button type="submit" class="btn btn-default">{{_('Submit')}}</button>
<a href="{{ url_for('show_book',id=book.id) }}" class="btn btn-default">{{_('Back')}}</a> <a href="{{ url_for('show_book', book_id=book.id) }}" class="btn btn-default">{{_('Back')}}</a>
</form> </form>
</div> </div>
{% endif %} {% endif %}
...@@ -138,7 +138,7 @@ ...@@ -138,7 +138,7 @@
{% block js %} {% block js %}
<script> <script>
var i18n_msg = { var i18nMsg = {
'loading': {{_('Loading...')|safe|tojson}}, 'loading': {{_('Loading...')|safe|tojson}},
'search_error': {{_('Search error!')|safe|tojson}}, 'search_error': {{_('Search error!')|safe|tojson}},
'no_result': {{_('No Result! Please try anonther keyword.')|safe|tojson}}, 'no_result': {{_('No Result! Please try anonther keyword.')|safe|tojson}},
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<h2>{{entry.title}}</h2> <h2>{{entry.title}}</h2>
<p class="author"> <p class="author">
{% for author in entry.authors %} {% for author in entry.authors %}
<a href="{{url_for('author', id=author.id ) }}">{{author.name}}</a> <a href="{{url_for('author', book_id=author.id ) }}">{{author.name}}</a>
{% if not loop.last %} {% if not loop.last %}
&amp; &amp;
{% endif %} {% endif %}
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
{% endif %} {% endif %}
{% if entry.series|length > 0 %} {% if entry.series|length > 0 %}
<p>{{_('Book')}} {{entry.series_index}} {{_('of')}} <a href="{{url_for('series', id=entry.series[0].id)}}">{{entry.series[0].name}}</a></p> <p>{{_('Book')}} {{entry.series_index}} {{_('of')}} <a href="{{url_for('series', book_id=entry.series[0].id)}}">{{entry.series[0].name}}</a></p>
{% endif %} {% endif %}
{% if entry.languages.__len__() > 0 %} {% if entry.languages.__len__() > 0 %}
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
<span class="glyphicon glyphicon-tags"></span> <span class="glyphicon glyphicon-tags"></span>
{% for tag in entry.tags %} {% for tag in entry.tags %}
<a href="{{ url_for('category', id=tag.id) }}" class="btn btn-xs btn-info" role="button">{{tag.name}}</a> <a href="{{ url_for('category', book_id=tag.id) }}" class="btn btn-xs btn-info" role="button">{{tag.name}}</a>
{%endfor%} {%endfor%}
</div> </div>
</p> </p>
...@@ -110,7 +110,7 @@ ...@@ -110,7 +110,7 @@
{% if not g.user.is_anonymous() %} {% if not g.user.is_anonymous() %}
<p> <p>
<div class="custom_columns" id="have_read_container"> <div class="custom_columns" id="have_read_container">
<form id="have_read_form" action="{{ url_for('toggle_read', id=entry.id)}}" method="POST") > <form id="have_read_form" action="{{ url_for('toggle_read', book_id=entry.id)}}" method="POST") >
<input id="have_read_cb" type="checkbox" {% if have_read %}checked{% endif %} > <input id="have_read_cb" type="checkbox" {% if have_read %}checked{% endif %} >
<label for="have_read_cb">{{_('Read')}}</label> <label for="have_read_cb">{{_('Read')}}</label>
</form> </form>
...@@ -136,7 +136,7 @@ ...@@ -136,7 +136,7 @@
</button> </button>
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop1"> <ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
{% for format in entry.data %} {% for format in entry.data %}
<li><a href="{{ url_for('get_download_link_ext', book_id=entry.id, format=format.format|lower, anyname=entry.id|string+'.'+format.format) }}">{{format.format}}</a></li> <li><a href="{{ url_for('get_download_link_ext', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format) }}">{{format.format}}</a></li>
{%endfor%} {%endfor%}
</ul> </ul>
</div> </div>
...@@ -154,7 +154,7 @@ ...@@ -154,7 +154,7 @@
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop2"> <ul class="dropdown-menu" aria-labelledby="btnGroupDrop2">
{% for format in entry.data %} {% for format in entry.data %}
{%if format.format|lower == 'epub' or format.format|lower == 'txt' or format.format|lower == 'pdf' or format.format|lower == 'cbr' or format.format|lower == 'cbt' or format.format|lower == 'cbz' %} {%if format.format|lower == 'epub' or format.format|lower == 'txt' or format.format|lower == 'pdf' or format.format|lower == 'cbr' or format.format|lower == 'cbt' or format.format|lower == 'cbz' %}
<li><a target="_blank" href="{{ url_for('read_book', book_id=entry.id, format=format.format|lower) }}">{{format.format}}</a></li> <li><a target="_blank" href="{{ url_for('read_book', book_id=entry.id, book_format=format.format|lower) }}">{{format.format}}</a></li>
{% endif %} {% endif %}
{%endfor%} {%endfor%}
</ul> </ul>
......
...@@ -8,14 +8,14 @@ ...@@ -8,14 +8,14 @@
<div class="col-sm-3 col-lg-2 col-xs-6 book"> <div class="col-sm-3 col-lg-2 col-xs-6 book">
<div class="cover"> <div class="cover">
{% if entry.has_cover is defined %} {% if entry.has_cover is defined %}
<a href="{{ url_for('show_book', id=entry.id) }}"> <a href="{{ url_for('show_book', book_id=entry.id) }}">
<img src="{{ url_for('get_cover', cover_path=entry.path.replace('\\','/')) }}" /> <img src="{{ url_for('get_cover', cover_path=entry.path.replace('\\','/')) }}" />
</a> </a>
{% endif %} {% endif %}
</div> </div>
<div class="meta"> <div class="meta">
<p class="title">{{entry.title|shortentitle}}</p> <p class="title">{{entry.title|shortentitle}}</p>
<p class="author"><a href="{{url_for('author', id=entry.authors[0].id) }}">{{entry.authors[0].name}}</a></p> <p class="author"><a href="{{url_for('author', book_id=entry.authors[0].id) }}">{{entry.authors[0].name}}</a></p>
{% if entry.ratings.__len__() > 0 %} {% if entry.ratings.__len__() > 0 %}
<div class="rating"> <div class="rating">
{% for number in range((entry.ratings[0].rating/2)|int(2)) %} {% for number in range((entry.ratings[0].rating/2)|int(2)) %}
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
<link type="image/jpeg" href="{{url_for('feed_get_cover', book_id=entry.id)}}" rel="http://opds-spec.org/image/thumbnail"/> <link type="image/jpeg" href="{{url_for('feed_get_cover', book_id=entry.id)}}" rel="http://opds-spec.org/image/thumbnail"/>
{% endif %} {% endif %}
{% for format in entry.data %} {% for format in entry.data %}
<link rel="http://opds-spec.org/acquisition" href="{{ url_for('get_opds_download_link', book_id=entry.id, format=format.format|lower)}}" <link rel="http://opds-spec.org/acquisition" href="{{ url_for('get_opds_download_link', book_id=entry.id, book_format=format.format|lower)}}"
length="{{format.uncompressed_size}}" mtime="{{entry.timestamp}}" type="{{format.format|lower|mimetype}}"/> length="{{format.uncompressed_size}}" mtime="{{entry.timestamp}}" type="{{format.format|lower|mimetype}}"/>
{% endfor %} {% endfor %}
</entry> </entry>
...@@ -65,9 +65,9 @@ ...@@ -65,9 +65,9 @@
{% for entry in listelements %} {% for entry in listelements %}
<entry> <entry>
<title>{{entry.name}}</title> <title>{{entry.name}}</title>
<id>{{ url_for(folder, id=entry.id) }}</id> <id>{{ url_for(folder, book_id=entry.id) }}</id>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for(folder, id=entry.id)}}"/> <link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for(folder, book_id=entry.id)}}"/>
<link type="application/atom+xml" href="{{url_for(folder, id=entry.id)}}" rel="subsection"/> <link type="application/atom+xml" href="{{url_for(folder, book_id=entry.id)}}" rel="subsection"/>
</entry> </entry>
{% endfor %} {% endfor %}
</feed> </feed>
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
{% for entry in random %} {% for entry in random %}
<div id="books_rand" class="col-sm-3 col-lg-2 col-xs-6 book"> <div id="books_rand" class="col-sm-3 col-lg-2 col-xs-6 book">
<div class="cover"> <div class="cover">
<a href="{{ url_for('show_book', id=entry.id) }}"> <a href="{{ url_for('show_book', book_id=entry.id) }}">
{% if entry.has_cover %} {% if entry.has_cover %}
<img src="{{ url_for('get_cover', cover_path=entry.path.replace('\\','/')) }}" /> <img src="{{ url_for('get_cover', cover_path=entry.path.replace('\\','/')) }}" />
{% else %} {% else %}
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
</div> </div>
<div class="meta"> <div class="meta">
<p class="title">{{entry.title|shortentitle}}</p> <p class="title">{{entry.title|shortentitle}}</p>
<p class="author"><a href="{{url_for('author', id=entry.authors[0].id) }}">{{entry.authors[0].name}}</a></p> <p class="author"><a href="{{url_for('author', book_id=entry.authors[0].id) }}">{{entry.authors[0].name}}</a></p>
{% if entry.ratings.__len__() > 0 %} {% if entry.ratings.__len__() > 0 %}
<div class="rating"> <div class="rating">
{% for number in range((entry.ratings[0].rating/2)|int(2)) %} {% for number in range((entry.ratings[0].rating/2)|int(2)) %}
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
{% for entry in entries %} {% for entry in entries %}
<div id="books" class="col-sm-3 col-lg-2 col-xs-6 book"> <div id="books" class="col-sm-3 col-lg-2 col-xs-6 book">
<div class="cover"> <div class="cover">
<a href="{{ url_for('show_book', id=entry.id) }}"> <a href="{{ url_for('show_book', book_id=entry.id) }}">
{% if entry.has_cover %} {% if entry.has_cover %}
<img src="{{ url_for('get_cover', cover_path=entry.path.replace('\\','/')) }}" /> <img src="{{ url_for('get_cover', cover_path=entry.path.replace('\\','/')) }}" />
{% else %} {% else %}
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
<p class="title">{{entry.title|shortentitle}}</p> <p class="title">{{entry.title|shortentitle}}</p>
<p class="author"> <p class="author">
{% for author in entry.authors %} {% for author in entry.authors %}
<a href="{{url_for('author', id=author.id) }}">{{author.name}}</a> <a href="{{url_for('author', book_id=author.id) }}">{{author.name}}</a>
{% if not loop.last %} {% if not loop.last %}
&amp; &amp;
{% endif %} {% endif %}
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
"timestamp": "{{entry.timestamp}}", "timestamp": "{{entry.timestamp}}",
"thumbnail": "{{url_for('feed_get_cover', book_id=entry.id)}}", "thumbnail": "{{url_for('feed_get_cover', book_id=entry.id)}}",
"main_format": { "main_format": {
"{{entry.data[0].format|lower}}": "{{ url_for('get_opds_download_link', book_id=entry.id, format=entry.data[0].format|lower)}}" "{{entry.data[0].format|lower}}": "{{ url_for('get_opds_download_link', book_id=entry.id, book_format=entry.data[0].format|lower)}}"
}, },
"rating":{% if entry.ratings.__len__() > 0 %} "{{entry.ratings[0].rating}}.0"{% else %}0.0{% endif %}, "rating":{% if entry.ratings.__len__() > 0 %} "{{entry.ratings[0].rating}}.0"{% else %}0.0{% endif %},
"authors": [ "authors": [
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
"other_formats": { "other_formats": {
{% if entry.data.__len__() > 1 %} {% if entry.data.__len__() > 1 %}
{% for format in entry.data[1:] %} {% for format in entry.data[1:] %}
"{{format.format|lower}}": "{{ url_for('get_opds_download_link', book_id=entry.id, format=format.format|lower)}}"{% if not loop.last %},{% endif %} "{{format.format|lower}}": "{{ url_for('get_opds_download_link', book_id=entry.id, book_format=format.format|lower)}}"{% if not loop.last %},{% endif %}
{% endfor %} {% endfor %}
{% endif %} }, {% endif %} },
"title_sort": "{{entry.sort}}" "title_sort": "{{entry.sort}}"
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
{% endif %} {% endif %}
<div class="row"> <div class="row">
<div class="col-xs-1" align="left"><span class="badge">{{entry.count}}</span></div> <div class="col-xs-1" align="left"><span class="badge">{{entry.count}}</span></div>
<div class="col-xs-6"><a id="list_{{loop.index0}}" href="{{url_for(folder, id=entry[0].id )}}">{{entry[0].name}}</a></div> <div class="col-xs-6"><a id="list_{{loop.index0}}" href="{{url_for(folder, book_id=entry[0].id )}}">{{entry[0].name}}</a></div>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<div class="col-sm-3 col-lg-2 col-xs-6 book"> <div class="col-sm-3 col-lg-2 col-xs-6 book">
<div class="cover"> <div class="cover">
{% if entry.has_cover is defined %} {% if entry.has_cover is defined %}
<a href="{{ url_for('show_book', id=entry.id) }}"> <a href="{{ url_for('show_book', book_id=entry.id) }}">
<img src="{{ url_for('get_cover', cover_path=entry.path.replace('\\','/')) }}" /> <img src="{{ url_for('get_cover', cover_path=entry.path.replace('\\','/')) }}" />
</a> </a>
{% endif %} {% endif %}
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
<p class="title">{{entry.title|shortentitle}}</p> <p class="title">{{entry.title|shortentitle}}</p>
<p class="author"> <p class="author">
{% for author in entry.authors %} {% for author in entry.authors %}
<a href="{{url_for('author', id=author.id ) }}">{{author.name}}</a> <a href="{{url_for('author', book_id=author.id ) }}">{{author.name}}</a>
{% if not loop.last %} {% if not loop.last %}
&amp; &amp;
{% endif %} {% endif %}
......
...@@ -15,14 +15,14 @@ ...@@ -15,14 +15,14 @@
<div class="col-sm-3 col-lg-2 col-xs-6 book"> <div class="col-sm-3 col-lg-2 col-xs-6 book">
<div class="cover"> <div class="cover">
{% if entry.has_cover is defined %} {% if entry.has_cover is defined %}
<a href="{{ url_for('show_book', id=entry.id) }}"> <a href="{{ url_for('show_book', book_id=entry.id) }}">
<img src="{{ url_for('get_cover', cover_path=entry.path.replace('\\','/')) }}" /> <img src="{{ url_for('get_cover', cover_path=entry.path.replace('\\','/')) }}" />
</a> </a>
{% endif %} {% endif %}
</div> </div>
<div class="meta"> <div class="meta">
<p class="title">{{entry.title|shortentitle}}</p> <p class="title">{{entry.title|shortentitle}}</p>
<p class="author"><a href="{{url_for('author', id=entry.authors[0].id) }}">{{entry.authors[0].name}}</a></p> <p class="author"><a href="{{url_for('author', book_id=entry.authors[0].id) }}">{{entry.authors[0].name}}</a></p>
{% if entry.ratings.__len__() > 0 %} {% if entry.ratings.__len__() > 0 %}
<div class="rating"> <div class="rating">
{% for number in range((entry.ratings[0].rating/2)|int(2)) %} {% for number in range((entry.ratings[0].rating/2)|int(2)) %}
......
...@@ -131,7 +131,7 @@ ...@@ -131,7 +131,7 @@
<h2>{{_('Recent Downloads')}}</h2> <h2>{{_('Recent Downloads')}}</h2>
{% for entry in downloads %} {% for entry in downloads %}
<div class="col-sm-2"> <div class="col-sm-2">
<a class="pull-left" href="{{ url_for('show_book', id=entry.id) }}"> <a class="pull-left" href="{{ url_for('show_book', book_id=entry.id) }}">
<img class="media-object" width="100" src="{{ url_for('get_cover', cover_path=entry.path.replace('\\','/')) }}" alt="..."> <img class="media-object" width="100" src="{{ url_for('get_cover', cover_path=entry.path.replace('\\','/')) }}" alt="...">
</a> </a>
</div> </div>
......
This diff is collapsed.
...@@ -307,7 +307,7 @@ msgstr "用户 '%(user)s' 已被创建" ...@@ -307,7 +307,7 @@ msgstr "用户 '%(user)s' 已被创建"
#: cps/web.py:2198 #: cps/web.py:2198
msgid "Found an existing account for this email address or nickname." msgid "Found an existing account for this email address or nickname."
msgstr "已找到使用此邮箱或昵称的账号。" msgstr "已存在使用此邮箱或昵称的账号。"
#: cps/web.py:2220 #: cps/web.py:2220
msgid "Mail settings updated" msgid "Mail settings updated"
...@@ -496,7 +496,7 @@ msgstr "最新提交时间戳" ...@@ -496,7 +496,7 @@ msgstr "最新提交时间戳"
#: cps/templates/admin.html:83 #: cps/templates/admin.html:83
msgid "Reconnect to Calibre DB" msgid "Reconnect to Calibre DB"
msgstr "" msgstr "重新连接到Calibre数据库"
#: cps/templates/admin.html:84 #: cps/templates/admin.html:84
msgid "Restart Calibre-web" msgid "Restart Calibre-web"
...@@ -590,7 +590,7 @@ msgstr "编辑后查看书籍" ...@@ -590,7 +590,7 @@ msgstr "编辑后查看书籍"
#: cps/templates/book_edit.html:107 cps/templates/book_edit.html:118 #: cps/templates/book_edit.html:107 cps/templates/book_edit.html:118
msgid "Get metadata" msgid "Get metadata"
msgstr "" msgstr "获取元数据"
#: cps/templates/book_edit.html:108 cps/templates/config_edit.html:117 #: cps/templates/book_edit.html:108 cps/templates/config_edit.html:117
#: cps/templates/login.html:19 cps/templates/search_form.html:79 #: cps/templates/login.html:19 cps/templates/search_form.html:79
...@@ -600,11 +600,11 @@ msgstr "提交" ...@@ -600,11 +600,11 @@ msgstr "提交"
#: cps/templates/book_edit.html:121 #: cps/templates/book_edit.html:121
msgid "Keyword" msgid "Keyword"
msgstr "" msgstr "关键字"
#: cps/templates/book_edit.html:122 #: cps/templates/book_edit.html:122
msgid " Search keyword " msgid " Search keyword "
msgstr "" msgstr "搜索关键字"
#: cps/templates/book_edit.html:124 cps/templates/layout.html:60 #: cps/templates/book_edit.html:124 cps/templates/layout.html:60
msgid "Go!" msgid "Go!"
...@@ -612,32 +612,32 @@ msgstr "走起!" ...@@ -612,32 +612,32 @@ msgstr "走起!"
#: cps/templates/book_edit.html:125 #: cps/templates/book_edit.html:125
msgid "Click the cover to load metadata to the form" msgid "Click the cover to load metadata to the form"
msgstr "" msgstr "点击封面加载元数据到表单"
#: cps/templates/book_edit.html:129 cps/templates/book_edit.html:142 #: cps/templates/book_edit.html:129 cps/templates/book_edit.html:142
msgid "Loading..." msgid "Loading..."
msgstr "" msgstr "加载中..."
#: cps/templates/book_edit.html:132 #: cps/templates/book_edit.html:132
msgid "Close" msgid "Close"
msgstr "" msgstr "关闭"
#: cps/templates/book_edit.html:143 #: cps/templates/book_edit.html:143
msgid "Search error!" msgid "Search error!"
msgstr "" msgstr "搜索错误"
#: cps/templates/book_edit.html:144 #: cps/templates/book_edit.html:144
msgid "No Result! Please try anonther keyword." msgid "No Result! Please try anonther keyword."
msgstr "" msgstr "没有结果!请尝试别的关键字."
#: cps/templates/book_edit.html:146 cps/templates/detail.html:76 #: cps/templates/book_edit.html:146 cps/templates/detail.html:76
#: cps/templates/search_form.html:14 #: cps/templates/search_form.html:14
msgid "Publisher" msgid "Publisher"
msgstr "" msgstr "出版社"
#: cps/templates/book_edit.html:148 #: cps/templates/book_edit.html:148
msgid "Source" msgid "Source"
msgstr "" msgstr "来源"
#: cps/templates/config_edit.html:7 #: cps/templates/config_edit.html:7
msgid "Location of Calibre database" msgid "Location of Calibre database"
...@@ -645,7 +645,7 @@ msgstr "Calibre 数据库位置" ...@@ -645,7 +645,7 @@ msgstr "Calibre 数据库位置"
#: cps/templates/config_edit.html:13 #: cps/templates/config_edit.html:13
msgid "Use google drive?" msgid "Use google drive?"
msgstr "" msgstr "是否使用google drive?"
#: cps/templates/config_edit.html:17 #: cps/templates/config_edit.html:17
msgid "Client id" msgid "Client id"
...@@ -660,8 +660,8 @@ msgid "Calibre Base URL" ...@@ -660,8 +660,8 @@ msgid "Calibre Base URL"
msgstr "" msgstr ""
#: cps/templates/config_edit.html:29 #: cps/templates/config_edit.html:29
msgid "Google drive Calibre folder" msgid "Google drive Calibre folde"
msgstr "" msgstr "Google drive Calibre 文件夹"
#: cps/templates/config_edit.html:38 #: cps/templates/config_edit.html:38
msgid "Metadata Watch Channel ID" msgid "Metadata Watch Channel ID"
...@@ -843,12 +843,12 @@ msgstr "显示随机书籍" ...@@ -843,12 +843,12 @@ msgstr "显示随机书籍"
#: cps/templates/index.xml:43 cps/templates/index.xml:47 #: cps/templates/index.xml:43 cps/templates/index.xml:47
#: cps/templates/layout.html:132 #: cps/templates/layout.html:132
msgid "Read Books" msgid "Read Books"
msgstr "" msgstr "已读书籍"
#: cps/templates/index.xml:50 cps/templates/index.xml:54 #: cps/templates/index.xml:50 cps/templates/index.xml:54
#: cps/templates/layout.html:133 #: cps/templates/layout.html:133
msgid "Unread Books" msgid "Unread Books"
msgstr "" msgstr "未读书籍"
#: cps/templates/index.xml:57 cps/templates/layout.html:144 #: cps/templates/index.xml:57 cps/templates/layout.html:144
msgid "Authors" msgid "Authors"
...@@ -1082,7 +1082,7 @@ msgstr "显示作者选择" ...@@ -1082,7 +1082,7 @@ msgstr "显示作者选择"
#: cps/templates/user_edit.html:75 #: cps/templates/user_edit.html:75
msgid "Show read and unread" msgid "Show read and unread"
msgstr "" msgstr "显示已读和未读"
#: cps/templates/user_edit.html:79 #: cps/templates/user_edit.html:79
msgid "Show random books in detail view" msgid "Show random books in detail view"
......
...@@ -13,7 +13,7 @@ from flask_babel import gettext as _ ...@@ -13,7 +13,7 @@ from flask_babel import gettext as _
import json import json
#from builtins import str #from builtins import str
dbpath = os.path.join(os.path.normpath(os.path.dirname(os.path.realpath(__file__)) + os.sep + ".." + os.sep), "app.db") dbpath = os.path.join(os.path.normpath(os.getenv("CALIBRE_DBPATH", os.path.dirname(os.path.realpath(__file__)) + os.sep + ".." + os.sep)), "app.db")
engine = create_engine('sqlite:///{0}'.format(dbpath), echo=False) engine = create_engine('sqlite:///{0}'.format(dbpath), echo=False)
Base = declarative_base() Base = declarative_base()
...@@ -64,10 +64,7 @@ class UserBase: ...@@ -64,10 +64,7 @@ class UserBase:
return False return False
def role_upload(self): def role_upload(self):
if self.role is not None: return bool((self.role is not None)and(self.role & ROLE_UPLOAD == ROLE_UPLOAD))
return True if self.role & ROLE_UPLOAD == ROLE_UPLOAD else False
else:
return False
def role_edit(self): def role_edit(self):
if self.role is not None: if self.role is not None:
...@@ -93,9 +90,11 @@ class UserBase: ...@@ -93,9 +90,11 @@ class UserBase:
else: else:
return False return False
@classmethod
def is_active(self): def is_active(self):
return True return True
@classmethod
def is_anonymous(self): def is_anonymous(self):
return False return False
...@@ -106,58 +105,31 @@ class UserBase: ...@@ -106,58 +105,31 @@ class UserBase:
return self.default_language return self.default_language
def show_random_books(self): def show_random_books(self):
if self.sidebar_view is not None: return bool((self.sidebar_view is not None)and(self.sidebar_view & SIDEBAR_RANDOM == SIDEBAR_RANDOM))
return True if self.sidebar_view & SIDEBAR_RANDOM == SIDEBAR_RANDOM else False
else:
return False
def show_language(self): def show_language(self):
if self.sidebar_view is not None: return bool((self.sidebar_view is not None)and(self.sidebar_view & SIDEBAR_LANGUAGE == SIDEBAR_LANGUAGE))
return True if self.sidebar_view & SIDEBAR_LANGUAGE == SIDEBAR_LANGUAGE else False
else:
return False
def show_hot_books(self): def show_hot_books(self):
if self.sidebar_view is not None: return bool((self.sidebar_view is not None)and(self.sidebar_view & SIDEBAR_HOT == SIDEBAR_HOT))
return True if self.sidebar_view & SIDEBAR_HOT == SIDEBAR_HOT else False
else:
return False
def show_series(self): def show_series(self):
if self.sidebar_view is not None: return bool((self.sidebar_view is not None)and(self.sidebar_view & SIDEBAR_SERIES == SIDEBAR_SERIES))
return True if self.sidebar_view & SIDEBAR_SERIES == SIDEBAR_SERIES else False
else:
return False
def show_category(self): def show_category(self):
if self.sidebar_view is not None: return bool((self.sidebar_view is not None)and(self.sidebar_view & SIDEBAR_CATEGORY == SIDEBAR_CATEGORY))
return True if self.sidebar_view & SIDEBAR_CATEGORY == SIDEBAR_CATEGORY else False
else:
return False
def show_author(self): def show_author(self):
if self.sidebar_view is not None: return bool((self.sidebar_view is not None)and(self.sidebar_view & SIDEBAR_AUTHOR == SIDEBAR_AUTHOR))
return True if self.sidebar_view & SIDEBAR_AUTHOR == SIDEBAR_AUTHOR else False
else:
return False
def show_best_rated_books(self): def show_best_rated_books(self):
if self.sidebar_view is not None: return bool((self.sidebar_view is not None)and(self.sidebar_view & SIDEBAR_BEST_RATED == SIDEBAR_BEST_RATED))
return True if self.sidebar_view & SIDEBAR_BEST_RATED == SIDEBAR_BEST_RATED else False
else:
return False
def show_read_and_unread(self): def show_read_and_unread(self):
if self.sidebar_view is not None: return bool((self.sidebar_view is not None)and(self.sidebar_view & SIDEBAR_READ_AND_UNREAD == SIDEBAR_READ_AND_UNREAD))
return True if self.sidebar_view & SIDEBAR_READ_AND_UNREAD == SIDEBAR_READ_AND_UNREAD else False
else:
return False
def show_detail_random(self): def show_detail_random(self):
if self.sidebar_view is not None: return bool((self.sidebar_view is not None)and(self.sidebar_view & DETAIL_RANDOM == DETAIL_RANDOM))
return True if self.sidebar_view & DETAIL_RANDOM == DETAIL_RANDOM else False
else:
return False
def __repr__(self): def __repr__(self):
return '<User %r>' % self.nickname return '<User %r>' % self.nickname
...@@ -321,10 +293,8 @@ class Config: ...@@ -321,10 +293,8 @@ class Config:
else: else:
self.config_google_drive_watch_changes_response=None self.config_google_drive_watch_changes_response=None
self.config_columns_to_ignore = data.config_columns_to_ignore self.config_columns_to_ignore = data.config_columns_to_ignore
if self.config_calibre_dir is not None and (not self.config_use_google_drive or os.path.exists(self.config_calibre_dir + '/metadata.db')): self.db_configured = bool(self.config_calibre_dir is not None and
self.db_configured = True (not self.config_use_google_drive or os.path.exists(self.config_calibre_dir + '/metadata.db')))
else:
self.db_configured = False
@property @property
def get_main_dir(self): def get_main_dir(self):
...@@ -506,9 +476,8 @@ def create_anonymous_user(): ...@@ -506,9 +476,8 @@ def create_anonymous_user():
session.add(user) session.add(user)
try: try:
session.commit() session.commit()
except Exception as e: except Exception:
session.rollback() session.rollback()
pass
# Generate User admin with admin123 password, and access to everything # Generate User admin with admin123 password, and access to everything
...@@ -525,9 +494,8 @@ def create_admin_user(): ...@@ -525,9 +494,8 @@ def create_admin_user():
session.add(user) session.add(user)
try: try:
session.commit() session.commit()
except Exception as e: except Exception:
session.rollback() session.rollback()
pass
# Open session for database connection # Open session for database connection
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment