mirror of
https://github.com/janeczku/calibre-web
synced 2024-12-25 09:30:31 +00:00
Merge remote-tracking branch 'refs/remotes/janeczku/master'
This commit is contained in:
commit
ccf563023b
2
cps.py
2
cps.py
@ -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')
|
||||||
|
26
cps/db.py
26
cps/db.py
@ -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):
|
|||||||
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):
|
|||||||
|
|
||||||
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):
|
|||||||
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():
|
|||||||
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():
|
|||||||
'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)
|
||||||
|
33
cps/epub.py
33
cps/epub.py
@ -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):
|
|||||||
'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):
|
|||||||
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):
|
|||||||
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 @@
|
|||||||
# -*- 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:
|
|||||||
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):
|
|||||||
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):
|
|||||||
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):
|
|||||||
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):
|
|||||||
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):
|
|||||||
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,
|
|||||||
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):
|
|||||||
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,
|
|||||||
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):
|
|||||||
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):
|
|||||||
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
|
|||||||
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
|
|||||||
|
|
||||||
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):
|
|||||||
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):
|
|||||||
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):
|
|||||||
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):
|
|||||||
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):
|
|||||||
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):
|
|||||||
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):
|
|||||||
|
|
||||||
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):
|
|||||||
|
|
||||||
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):
|
|||||||
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):
|
|||||||
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):
|
|||||||
# 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):
|
|||||||
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)
|
||||||
|
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
/**
|
/**
|
||||||
* 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) {
|
|||||||
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 series = new Bloodhound({
|
||||||
var bh_adapter = authors.ttAdapter();
|
name: "series",
|
||||||
|
datumTokenizer(datum) {
|
||||||
|
return [datum.name];
|
||||||
|
},
|
||||||
|
queryTokenizer(query) {
|
||||||
|
return [query];
|
||||||
|
},
|
||||||
|
remote: {
|
||||||
|
url: getPath()+"/get_series_json?q=",
|
||||||
|
replace(url, query) {
|
||||||
|
return url+encodeURIComponent(query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var tokens = query.split("&");
|
|
||||||
var current_author = tokens[tokens.length-1].trim();
|
var tags = new Bloodhound({
|
||||||
|
name: "tags",
|
||||||
|
datumTokenizer(datum) {
|
||||||
|
return [datum.name];
|
||||||
|
},
|
||||||
|
queryTokenizer(query) {
|
||||||
|
var tokens = query.split(",");
|
||||||
|
tokens = [tokens[tokens.length-1].trim()];
|
||||||
|
return tokens;
|
||||||
|
},
|
||||||
|
remote: {
|
||||||
|
url: getPath()+"/get_tags_json?q=%QUERY"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var languages = new Bloodhound({
|
||||||
|
name: "languages",
|
||||||
|
datumTokenizer(datum) {
|
||||||
|
return [datum.name];
|
||||||
|
},
|
||||||
|
queryTokenizer(query) {
|
||||||
|
return [query];
|
||||||
|
},
|
||||||
|
remote: {
|
||||||
|
url: getPath()+"/get_languages_json?q=",
|
||||||
|
replace(url, query) {
|
||||||
|
return url+encodeURIComponent(query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function sourceSplit(query, cb, split, source) {
|
||||||
|
var bhAdapter = source.ttAdapter();
|
||||||
|
|
||||||
|
var tokens = query.split(split);
|
||||||
|
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 = "";
|
||||||
for (var i = 0; i < tokens.length; i++) {
|
var newSplit;
|
||||||
var author = tokens[i].trim();
|
if (split === "&"){
|
||||||
prefix += author + " & ";
|
newSplit = " " + split + " ";
|
||||||
|
}else{
|
||||||
|
newSplit = split + " ";
|
||||||
}
|
}
|
||||||
|
for (var i = 0; i < tokens.length; i++) {
|
||||||
prefixed_source(prefix, current_author, cb, bh_adapter);
|
prefix += tokens[i].trim() + newSplit;
|
||||||
|
}
|
||||||
|
prefixedSource(prefix, currentSource, cb, bhAdapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var promiseAuthors = authors.initialize();
|
||||||
|
promiseAuthors.done(function(){
|
||||||
var promise = authors.initialize();
|
|
||||||
promise.done(function(){
|
|
||||||
$("#bookAuthor").typeahead(
|
$("#bookAuthor").typeahead(
|
||||||
{
|
{
|
||||||
highlight: true, minLength: 1,
|
highlight: true, minLength: 1,
|
||||||
hint: true
|
hint: true
|
||||||
}, {
|
}, {
|
||||||
name: 'authors', displayKey: 'name',
|
name: "authors",
|
||||||
source: authors_source
|
displayKey: "name",
|
||||||
|
source(query, cb){
|
||||||
|
return sourceSplit(query, cb, "&", authors); //sourceSplit //("&")
|
||||||
}
|
}
|
||||||
)
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var series = new Bloodhound({
|
var promiseSeries = series.initialize();
|
||||||
name: 'series',
|
promiseSeries.done(function(){
|
||||||
datumTokenizer: function(datum) {
|
|
||||||
return [datum.name];
|
|
||||||
},
|
|
||||||
queryTokenizer: function(query) {
|
|
||||||
return [query];
|
|
||||||
},
|
|
||||||
remote: {
|
|
||||||
url: get_path()+'/get_series_json?q=',
|
|
||||||
replace: function(url, query) {
|
|
||||||
url_query = url+encodeURIComponent(query);
|
|
||||||
return url_query;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
var promise = series.initialize();
|
|
||||||
promise.done(function(){
|
|
||||||
$("#series").typeahead(
|
$("#series").typeahead(
|
||||||
{
|
{
|
||||||
highlight: true, minLength: 0,
|
highlight: true, minLength: 0,
|
||||||
hint: true
|
hint: true
|
||||||
}, {
|
}, {
|
||||||
name: 'series', displayKey: 'name',
|
name: "series",
|
||||||
|
displayKey: "name",
|
||||||
source: series.ttAdapter()
|
source: series.ttAdapter()
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
var tags = new Bloodhound({
|
var promiseTags = tags.initialize();
|
||||||
name: 'tags',
|
promiseTags.done(function(){
|
||||||
datumTokenizer: function(datum) {
|
|
||||||
return [datum.name];
|
|
||||||
},
|
|
||||||
queryTokenizer: function(query) {
|
|
||||||
tokens = query.split(",");
|
|
||||||
tokens = [tokens[tokens.length-1].trim()];
|
|
||||||
return tokens
|
|
||||||
},
|
|
||||||
remote: {
|
|
||||||
url: get_path()+'/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(
|
$("#tags").typeahead(
|
||||||
{
|
{
|
||||||
highlight: true, minLength: 0,
|
highlight: true, minLength: 0,
|
||||||
hint: true
|
hint: true
|
||||||
}, {
|
}, {
|
||||||
name: 'tags', displayKey: 'name',
|
name: "tags",
|
||||||
source: tag_source
|
displayKey: "name",
|
||||||
}
|
source(query, cb){
|
||||||
)
|
return sourceSplit(query, cb, ",", tags);
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
var languages = new Bloodhound({
|
var promiseLanguages = languages.initialize();
|
||||||
name: 'languages',
|
promiseLanguages.done(function(){
|
||||||
datumTokenizer: function(datum) {
|
|
||||||
return [datum.name];
|
|
||||||
},
|
|
||||||
queryTokenizer: function(query) {
|
|
||||||
return [query];
|
|
||||||
},
|
|
||||||
remote: {
|
|
||||||
url: get_path()+'/get_languages_json?q=',
|
|
||||||
replace: function(url, query) {
|
|
||||||
url_query = url+encodeURIComponent(query);
|
|
||||||
return url_query;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function language_source(query, cb) {
|
|
||||||
var bh_adapter = languages.ttAdapter();
|
|
||||||
|
|
||||||
var tokens = query.split(",");
|
|
||||||
var current_language = 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_language, cb, bh_adapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
var promise = languages.initialize();
|
|
||||||
promise.done(function(){
|
|
||||||
$("#languages").typeahead(
|
$("#languages").typeahead(
|
||||||
{
|
{
|
||||||
highlight: true, minLength: 0,
|
highlight: true, minLength: 0,
|
||||||
hint: true
|
hint: true
|
||||||
}, {
|
}, {
|
||||||
name: 'languages', displayKey: 'name',
|
name: "languages",
|
||||||
source: language_source
|
displayKey: "name",
|
||||||
}
|
source(query, cb){
|
||||||
)
|
return sourceSplit(query, cb, ",", languages); //(",")
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
$('form').on('change input typeahead:selected', function(data){
|
$("form").on("change input typeahead:selected", function(data){
|
||||||
form = $('form').serialize();
|
var form = $("form").serialize();
|
||||||
$.getJSON( get_path()+"/get_matching_tags", form, function( data ) {
|
$.getJSON( getPath()+"/get_matching_tags", form, function( data ) {
|
||||||
$('.tags_click').each(function() {
|
$(".tags_click").each(function() {
|
||||||
if ($.inArray(parseInt($(this).children('input').first().val(), 10), data.tags) == -1 ) {
|
if ($.inArray(parseInt($(this).children("input").first().val(), 10), data.tags) === -1 ) {
|
||||||
if (!($(this).hasClass('active'))) {
|
if (!($(this).hasClass("active"))) {
|
||||||
$(this).addClass('disabled');
|
$(this).addClass("disabled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$(this).removeClass('disabled');
|
$(this).removeClass("disabled");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -4,176 +4,182 @@
|
|||||||
* Google Books api document: https://developers.google.com/books/docs/v1/using
|
* Google Books api document: https://developers.google.com/books/docs/v1/using
|
||||||
* Douban Books api document: https://developers.douban.com/wiki/?title=book_v2 (Chinese Only)
|
* Douban Books api document: https://developers.douban.com/wiki/?title=book_v2 (Chinese Only)
|
||||||
*/
|
*/
|
||||||
|
/* global i18nMsg */
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
var msg = i18n_msg;
|
var msg = i18nMsg;
|
||||||
var douban = 'https://api.douban.com';
|
var douban = "https://api.douban.com";
|
||||||
var db_search = '/v2/book/search';
|
var dbSearch = "/v2/book/search";
|
||||||
var db_get_info = '/v2/book/';
|
// var dbGetInfo = "/v2/book/";
|
||||||
var db_get_info_by_isbn = '/v2/book/isbn/ ';
|
// var db_get_info_by_isbn = "/v2/book/isbn/ ";
|
||||||
var db_done = false;
|
var dbDone = false;
|
||||||
|
|
||||||
var google = 'https://www.googleapis.com/';
|
var google = "https://www.googleapis.com/";
|
||||||
var gg_search = '/books/v1/volumes';
|
var ggSearch = "/books/v1/volumes";
|
||||||
var gg_get_info = '/books/v1/volumes/';
|
// var gg_get_info = "/books/v1/volumes/";
|
||||||
var gg_done = false;
|
var ggDone = false;
|
||||||
|
|
||||||
var db_results = [];
|
var dbResults = [];
|
||||||
var gg_results = [];
|
var ggResults = [];
|
||||||
var show_flag = 0;
|
var showFlag = 0;
|
||||||
String.prototype.replaceAll = function (s1, s2) {
|
String.prototype.replaceAll = function (s1, s2) {
|
||||||
return this.replace(new RegExp(s1, "gm"), s2);
|
return this.replace(new RegExp(s1, "gm"), s2);
|
||||||
}
|
};
|
||||||
|
|
||||||
gg_search_book = function (title) {
|
function showResult () {
|
||||||
title = title.replaceAll(/\s+/, '+');
|
var book;
|
||||||
var url = google + gg_search + '?q=' + title;
|
var i;
|
||||||
$.ajax({
|
var bookHtml;
|
||||||
url: url,
|
showFlag++;
|
||||||
type: "GET",
|
if (showFlag === 1) {
|
||||||
dataType: "jsonp",
|
$("#meta-info").html("<ul id=\"book-list\" class=\"media-list\"></ul>");
|
||||||
jsonp: 'callback',
|
|
||||||
success: function (data) {
|
|
||||||
gg_results = data.items;
|
|
||||||
},
|
|
||||||
complete: function () {
|
|
||||||
gg_done = true;
|
|
||||||
show_result();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get_meta = function (source, id) {
|
|
||||||
var meta;
|
|
||||||
if (source == 'google') {;
|
|
||||||
meta = gg_results[id];
|
|
||||||
$('#description').val(meta.volumeInfo.description);
|
|
||||||
$('#bookAuthor').val(meta.volumeInfo.authors.join(' & '));
|
|
||||||
$('#book_title').val(meta.volumeInfo.title);
|
|
||||||
if (meta.volumeInfo.categories) {
|
|
||||||
var tags = meta.volumeInfo.categories.join(',');
|
|
||||||
$('#tags').val(tags);
|
|
||||||
}
|
|
||||||
if (meta.volumeInfo.averageRating) {
|
|
||||||
$('#rating').val(Math.round(meta.volumeInfo.averageRating));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (source == 'douban') {
|
if (ggDone && dbDone) {
|
||||||
meta = db_results[id];
|
if (!ggResults && !dbResults) {
|
||||||
$('#description').val(meta.summary);
|
$("#meta-info").html("<p class=\"text-danger\">"+ msg.no_result +"</p>");
|
||||||
$('#bookAuthor').val(meta.author.join(' & '));
|
|
||||||
$('#book_title').val(meta.title);
|
|
||||||
var tags = '';
|
|
||||||
for (var i = 0; i < meta.tags.length; i++) {
|
|
||||||
tags = tags + meta.tags[i].title + ',';
|
|
||||||
}
|
|
||||||
$('#tags').val(tags);
|
|
||||||
$('#rating').val(Math.round(meta.rating.average / 2));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do_search = function (keyword) {
|
|
||||||
show_flag = 0;
|
|
||||||
$('#meta-info').text(msg.loading);
|
|
||||||
var keyword = $('#keyword').val();
|
|
||||||
if (keyword) {
|
|
||||||
db_search_book(keyword);
|
|
||||||
gg_search_book(keyword);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
db_search_book = function (title) {
|
|
||||||
var url = douban + db_search + '?q=' + title + '&fields=all&count=10';
|
|
||||||
$.ajax({
|
|
||||||
url: url,
|
|
||||||
type: "GET",
|
|
||||||
dataType: "jsonp",
|
|
||||||
jsonp: 'callback',
|
|
||||||
success: function (data) {
|
|
||||||
db_results = data.books;
|
|
||||||
},
|
|
||||||
error: function () {
|
|
||||||
$('#meta-info').html('<p class="text-danger">'+ msg.search_error+'!</p>');
|
|
||||||
},
|
|
||||||
complete: function () {
|
|
||||||
db_done = true;
|
|
||||||
show_result();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
show_result = function () {
|
|
||||||
show_flag++;
|
|
||||||
if (show_flag == 1) {
|
|
||||||
$('#meta-info').html('<ul id="book-list" class="media-list"></ul>');
|
|
||||||
}
|
|
||||||
if (gg_done && db_done) {
|
|
||||||
if (!gg_results && !db_results) {
|
|
||||||
$('#meta-info').html('<p class="text-danger">'+ msg.no_result +'</p>');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (gg_done && gg_results.length > 0) {
|
if (ggDone && ggResults.length > 0) {
|
||||||
for (var i = 0; i < gg_results.length; i++) {
|
for (i = 0; i < ggResults.length; i++) {
|
||||||
var book = gg_results[i];
|
book = ggResults[i];
|
||||||
var book_cover;
|
var bookCover;
|
||||||
if (book.volumeInfo.imageLinks) {
|
if (book.volumeInfo.imageLinks) {
|
||||||
book_cover = book.volumeInfo.imageLinks.thumbnail;
|
bookCover = book.volumeInfo.imageLinks.thumbnail;
|
||||||
} else {
|
} else {
|
||||||
book_cover = '/static/generic_cover.jpg';
|
bookCover = "/static/generic_cover.jpg";
|
||||||
}
|
}
|
||||||
var book_html = '<li class="media">' +
|
bookHtml = "<li class=\"media\">" +
|
||||||
'<img class="pull-left img-responsive" data-toggle="modal" data-target="#metaModal" src="' +
|
"<img class=\"pull-left img-responsive\" data-toggle=\"modal\" data-target=\"#metaModal\" src=\"" +
|
||||||
book_cover + '" alt="Cover" style="width:100px;height:150px" onclick=\'javascript:get_meta("google",' +
|
bookCover + "\" alt=\"Cover\" style=\"width:100px;height:150px\" onclick='javascript:getMeta(\"google\"," +
|
||||||
i + ')\'>' +
|
i + ")\\>\"" +
|
||||||
'<div class="media-body">' +
|
"<div class=\"media-body\">" +
|
||||||
'<h4 class="media-heading"><a href="https://books.google.com/books?id=' +
|
"<h4 class=\"media-heading\"><a href=\"https://books.google.com/books?id=" +
|
||||||
book.id + '" target="_blank">' + book.volumeInfo.title + '</a></h4>' +
|
book.id + "\" target=\"_blank\">" + book.volumeInfo.title + "</a></h4>" +
|
||||||
'<p>'+ msg.author +':' + book.volumeInfo.authors + '</p>' +
|
"<p>"+ msg.author +":" + book.volumeInfo.authors + "</p>" +
|
||||||
'<p>'+ msg.publisher + ':' + book.volumeInfo.publisher + '</p>' +
|
"<p>"+ msg.publisher + ":" + book.volumeInfo.publisher + "</p>" +
|
||||||
'<p>'+ msg.description + ':' + book.volumeInfo.description + '</p>' +
|
"<p>"+ msg.description + ":" + book.volumeInfo.description + "</p>" +
|
||||||
'<p>'+ msg.source + ':<a href="https://books.google.com" target="_blank">Google Books</a></p>' +
|
"<p>"+ msg.source + ":<a href=\"https://books.google.com\" target=\"_blank\">Google Books</a></p>" +
|
||||||
'</div>' +
|
"</div>" +
|
||||||
'</li>';
|
"</li>";
|
||||||
$("#book-list").append(book_html);
|
$("#book-list").append(bookHtml);
|
||||||
}
|
}
|
||||||
gg_done = false;
|
ggDone = false;
|
||||||
}
|
}
|
||||||
if (db_done && db_results.length > 0) {
|
if (dbDone && dbResults.length > 0) {
|
||||||
for (var i = 0; i < db_results.length; i++) {
|
for (i = 0; i < dbResults.length; i++) {
|
||||||
var book = db_results[i];
|
book = dbResults[i];
|
||||||
var book_html = '<li class="media">' +
|
bookHtml = "<li class=\"media\">" +
|
||||||
'<img class="pull-left img-responsive" data-toggle="modal" data-target="#metaModal" src="' +
|
"<img class=\"pull-left img-responsive\" data-toggle=\"modal\" data-target=\"#metaModal\" src=\"" +
|
||||||
book.image + '" alt="Cover" style="width:100px;height: 150px" onclick=\'javascript:get_meta("douban",' +
|
book.image + "\" alt=\"Cover\" style=\"width:100px;height: 150px\" onclick='javascript:getMeta(\"douban\"," +
|
||||||
i + ')\'>' +
|
i + ")\\'>" +
|
||||||
'<div class="media-body">' +
|
"<div class=\"media-body\">" +
|
||||||
'<h4 class="media-heading"><a href="https://book.douban.com/subject/' +
|
"<h4 class=\"media-heading\"><a href=\"https://book.douban.com/subject/" +
|
||||||
book.id + '" target="_blank">' + book.title + '</a></h4>' +
|
book.id + "\" target=\"_blank\">" + book.title + "</a></h4>" +
|
||||||
'<p>' + msg.author + ':' + book.author + '</p>' +
|
"<p>" + msg.author + ":" + book.author + "</p>" +
|
||||||
'<p>' + msg.publisher + ':' + book.publisher + '</p>' +
|
"<p>" + msg.publisher + ":" + book.publisher + "</p>" +
|
||||||
'<p>' + msg.description + ':' + book.summary + '</p>' +
|
"<p>" + msg.description + ":" + book.summary + "</p>" +
|
||||||
'<p>' + msg.source + ':<a href="https://book.douban.com" target="_blank">Douban Books</a></p>' +
|
"<p>" + msg.source + ":<a href=\"https://book.douban.com\" target=\"_blank\">Douban Books</a></p>" +
|
||||||
'</div>' +
|
"</div>" +
|
||||||
'</li>';
|
"</li>";
|
||||||
$("#book-list").append(book_html);
|
$("#book-list").append(bookHtml);
|
||||||
}
|
}
|
||||||
db_done = false;
|
dbDone = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#do-search').click(function () {
|
function ggSearchBook (title) {
|
||||||
var keyword = $('#keyword').val();
|
title = title.replaceAll(/\s+/, "+");
|
||||||
|
var url = google + ggSearch + "?q=" + title;
|
||||||
|
$.ajax({
|
||||||
|
url,
|
||||||
|
type: "GET",
|
||||||
|
dataType: "jsonp",
|
||||||
|
jsonp: "callback",
|
||||||
|
success (data) {
|
||||||
|
ggResults = data.items;
|
||||||
|
},
|
||||||
|
complete () {
|
||||||
|
ggDone = true;
|
||||||
|
showResult();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMeta (source, id) {
|
||||||
|
var meta;
|
||||||
|
var tags;
|
||||||
|
if (source === "google") {
|
||||||
|
meta = ggResults[id];
|
||||||
|
$("#description").val(meta.volumeInfo.description);
|
||||||
|
$("#bookAuthor").val(meta.volumeInfo.authors.join(" & "));
|
||||||
|
$("#book_title").val(meta.volumeInfo.title);
|
||||||
|
if (meta.volumeInfo.categories) {
|
||||||
|
tags = meta.volumeInfo.categories.join(",");
|
||||||
|
$("#tags").val(tags);
|
||||||
|
}
|
||||||
|
if (meta.volumeInfo.averageRating) {
|
||||||
|
$("#rating").val(Math.round(meta.volumeInfo.averageRating));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (source === "douban") {
|
||||||
|
meta = dbResults[id];
|
||||||
|
$("#description").val(meta.summary);
|
||||||
|
$("#bookAuthor").val(meta.author.join(" & "));
|
||||||
|
$("#book_title").val(meta.title);
|
||||||
|
tags = "";
|
||||||
|
for (var i = 0; i < meta.tags.length; i++) {
|
||||||
|
tags = tags + meta.tags[i].title + ",";
|
||||||
|
}
|
||||||
|
$("#tags").val(tags);
|
||||||
|
$("#rating").val(Math.round(meta.rating.average / 2));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dbSearchBook (title) {
|
||||||
|
var url = douban + dbSearch + "?q=" + title + "&fields=all&count=10";
|
||||||
|
$.ajax({
|
||||||
|
url,
|
||||||
|
type: "GET",
|
||||||
|
dataType: "jsonp",
|
||||||
|
jsonp: "callback",
|
||||||
|
success (data) {
|
||||||
|
dbResults = data.books;
|
||||||
|
},
|
||||||
|
error () {
|
||||||
|
$("#meta-info").html("<p class=\"text-danger\">"+ msg.search_error+"!</p>");
|
||||||
|
},
|
||||||
|
complete () {
|
||||||
|
dbDone = true;
|
||||||
|
showResult();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSearch (keyword) {
|
||||||
|
showFlag = 0;
|
||||||
|
$("#meta-info").text(msg.loading);
|
||||||
|
// var keyword = $("#keyword").val();
|
||||||
if (keyword) {
|
if (keyword) {
|
||||||
do_search(keyword);
|
dbSearchBook(keyword);
|
||||||
|
ggSearchBook(keyword);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#do-search").click(function () {
|
||||||
|
var keyword = $("#keyword").val();
|
||||||
|
if (keyword) {
|
||||||
|
doSearch(keyword);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#get_meta').click(function () {
|
$("#get_meta").click(function () {
|
||||||
var book_title = $('#book_title').val();
|
var bookTitle = $("#book_title").val();
|
||||||
if (book_title) {
|
if (bookTitle) {
|
||||||
$('#keyword').val(book_title);
|
$("#keyword").val(bookTitle);
|
||||||
do_search(book_title);
|
doSearch(bookTitle);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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() {
|
|||||||
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);}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
|
$(window).resize(function(event) {
|
||||||
function restartTimer() {
|
$(".discover .row").isotope("reLayout");
|
||||||
$('#spinner').hide();
|
|
||||||
$('#RestartDialog').modal('hide');
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateTimer() {
|
|
||||||
$.ajax({
|
|
||||||
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
|
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
|
||||||
|
|
||||||
$(window).resize(function(event) {
|
|
||||||
$('.discover .row').isotope('reLayout');
|
|
||||||
});
|
|
@ -1,4 +1,6 @@
|
|||||||
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){
|
|||||||
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 @@
|
|||||||
</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 @@
|
|||||||
|
|
||||||
{% 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 @@
|
|||||||
<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 %}
|
||||||
&
|
&
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -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 @@
|
|||||||
<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 @@
|
|||||||
{% 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 @@
|
|||||||
</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 @@
|
|||||||
<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 @@
|
|||||||
<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 @@
|
|||||||
<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 @@
|
|||||||
{% 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 @@
|
|||||||
{% 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 @@
|
|||||||
</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 @@
|
|||||||
{% 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 @@
|
|||||||
<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 %}
|
||||||
&
|
&
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -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 @@
|
|||||||
"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 @@
|
|||||||
{% 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 @@
|
|||||||
<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 @@
|
|||||||
<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 %}
|
||||||
&
|
&
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -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 @@
|
|||||||
<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>
|
||||||
|
Binary file not shown.
@ -12,18 +12,19 @@
|
|||||||
# Jellby <jellby@yahoo.com>, 2014-2015# Translation template file..
|
# Jellby <jellby@yahoo.com>, 2014-2015# Translation template file..
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Calibre-web\n"
|
"Project-Id-Version: Calibre-web\n"
|
||||||
"Report-Msgid-Bugs-To: https://github.com/janeczku/calibre-web\n"
|
"Report-Msgid-Bugs-To: https://github.com/janeczku/calibre-web\n"
|
||||||
"POT-Creation-Date: 2017-03-19 19:20+0100\n"
|
"POT-Creation-Date: 2017-03-19 19:20+0100\n"
|
||||||
"PO-Revision-Date: 2016-11-13 18:35+0100\n"
|
"PO-Revision-Date: 2017-04-04 15:09+0200\n"
|
||||||
"Last-Translator: Juan F. Villa <juan.villa@paisdelconocimiento.org>\n"
|
"Last-Translator: Juan F. Villa <juan.villa@paisdelconocimiento.org>\n"
|
||||||
"Language: es\n"
|
"Language: es\n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Generated-By: Babel 2.3.4\n"
|
"Generated-By: Babel 2.3.4\n"
|
||||||
|
"X-Generator: Poedit 1.8.7.1\n"
|
||||||
|
|
||||||
#: cps/book_formats.py:113 cps/book_formats.py:117 cps/web.py:1244
|
#: cps/book_formats.py:113 cps/book_formats.py:117 cps/web.py:1244
|
||||||
msgid "not installed"
|
msgid "not installed"
|
||||||
@ -56,35 +57,35 @@ msgstr "No fue posible convertir de epub a mobi"
|
|||||||
|
|
||||||
#: cps/ub.py:488
|
#: cps/ub.py:488
|
||||||
msgid "Guest"
|
msgid "Guest"
|
||||||
msgstr ""
|
msgstr "Invitado"
|
||||||
|
|
||||||
#: cps/web.py:904
|
#: cps/web.py:904
|
||||||
msgid "Requesting update package"
|
msgid "Requesting update package"
|
||||||
msgstr ""
|
msgstr "Solicitando paquete de actualización"
|
||||||
|
|
||||||
#: cps/web.py:905
|
#: cps/web.py:905
|
||||||
msgid "Downloading update package"
|
msgid "Downloading update package"
|
||||||
msgstr ""
|
msgstr "Descargando paquete de actualización"
|
||||||
|
|
||||||
#: cps/web.py:906
|
#: cps/web.py:906
|
||||||
msgid "Unzipping update package"
|
msgid "Unzipping update package"
|
||||||
msgstr ""
|
msgstr "Descomprimiendo paquete de actualización"
|
||||||
|
|
||||||
#: cps/web.py:907
|
#: cps/web.py:907
|
||||||
msgid "Files are replaced"
|
msgid "Files are replaced"
|
||||||
msgstr ""
|
msgstr "Ficheros sustituidos"
|
||||||
|
|
||||||
#: cps/web.py:908
|
#: cps/web.py:908
|
||||||
msgid "Database connections are closed"
|
msgid "Database connections are closed"
|
||||||
msgstr ""
|
msgstr "Los conexiones de base datos están cerradas"
|
||||||
|
|
||||||
#: cps/web.py:909
|
#: cps/web.py:909
|
||||||
msgid "Server is stopped"
|
msgid "Server is stopped"
|
||||||
msgstr ""
|
msgstr "El servidor está detenido"
|
||||||
|
|
||||||
#: cps/web.py:910
|
#: cps/web.py:910
|
||||||
msgid "Update finished, please press okay and reload page"
|
msgid "Update finished, please press okay and reload page"
|
||||||
msgstr ""
|
msgstr "Actualización finalizada. Por favor, pulse OK y recargue la página"
|
||||||
|
|
||||||
#: cps/web.py:983
|
#: cps/web.py:983
|
||||||
msgid "Latest Books"
|
msgid "Latest Books"
|
||||||
@ -92,33 +93,33 @@ msgstr "Libros recientes"
|
|||||||
|
|
||||||
#: cps/web.py:1014
|
#: cps/web.py:1014
|
||||||
msgid "Hot Books (most downloaded)"
|
msgid "Hot Books (most downloaded)"
|
||||||
msgstr "Libros Populares (los mas descargados)"
|
msgstr "Libros populares (los mas descargados)"
|
||||||
|
|
||||||
#: cps/web.py:1024
|
#: cps/web.py:1024
|
||||||
msgid "Best rated books"
|
msgid "Best rated books"
|
||||||
msgstr ""
|
msgstr "Libros mejor valorados"
|
||||||
|
|
||||||
#: cps/templates/index.xml:36 cps/web.py:1033
|
#: cps/templates/index.xml:36 cps/web.py:1033
|
||||||
msgid "Random Books"
|
msgid "Random Books"
|
||||||
msgstr "Libros al Azar"
|
msgstr "Libros al azar"
|
||||||
|
|
||||||
#: cps/web.py:1046
|
#: cps/web.py:1046
|
||||||
msgid "Author list"
|
msgid "Author list"
|
||||||
msgstr "Lista de Autores"
|
msgstr "Lista de autores"
|
||||||
|
|
||||||
#: cps/web.py:1057
|
#: cps/web.py:1057
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Author: %(name)s"
|
msgid "Author: %(name)s"
|
||||||
msgstr ""
|
msgstr "Autor:%(name)s"
|
||||||
|
|
||||||
#: cps/web.py:1059 cps/web.py:1087 cps/web.py:1221 cps/web.py:1626
|
#: cps/web.py:1059 cps/web.py:1087 cps/web.py:1221 cps/web.py:1626
|
||||||
#: cps/web.py:2579
|
#: cps/web.py:2579
|
||||||
msgid "Error opening eBook. File does not exist or file is not accessible:"
|
msgid "Error opening eBook. File does not exist or file is not accessible:"
|
||||||
msgstr "Error en apertura del Objeto. El archivo no existe o no es accesible"
|
msgstr "Error en la apertura del eBook. El archivo no existe o no es accesible:"
|
||||||
|
|
||||||
#: cps/templates/index.xml:71 cps/web.py:1073
|
#: cps/templates/index.xml:71 cps/web.py:1073
|
||||||
msgid "Series list"
|
msgid "Series list"
|
||||||
msgstr "lista de Series"
|
msgstr "Lista de series"
|
||||||
|
|
||||||
#: cps/web.py:1085
|
#: cps/web.py:1085
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -136,12 +137,12 @@ msgstr "Lenguaje: %(name)s"
|
|||||||
|
|
||||||
#: cps/templates/index.xml:64 cps/web.py:1146
|
#: cps/templates/index.xml:64 cps/web.py:1146
|
||||||
msgid "Category list"
|
msgid "Category list"
|
||||||
msgstr "Lista de Categorias"
|
msgstr "Lista de categorias"
|
||||||
|
|
||||||
#: cps/web.py:1158
|
#: cps/web.py:1158
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Category: %(name)s"
|
msgid "Category: %(name)s"
|
||||||
msgstr "Categoria : %(name)s"
|
msgstr "Categoría : %(name)s"
|
||||||
|
|
||||||
#: cps/web.py:1267
|
#: cps/web.py:1267
|
||||||
msgid "Statistics"
|
msgid "Statistics"
|
||||||
@ -149,39 +150,39 @@ msgstr "Estadisticas"
|
|||||||
|
|
||||||
#: cps/web.py:1375
|
#: cps/web.py:1375
|
||||||
msgid "Server restarted, please reload page"
|
msgid "Server restarted, please reload page"
|
||||||
msgstr ""
|
msgstr "Servidor reiniciado. Por favor, recargue la página"
|
||||||
|
|
||||||
#: cps/web.py:1377
|
#: cps/web.py:1377
|
||||||
msgid "Performing shutdown of server, please close window"
|
msgid "Performing shutdown of server, please close window"
|
||||||
msgstr ""
|
msgstr "Servidor en proceso de apagado. Por favor, cierre la ventana."
|
||||||
|
|
||||||
#: cps/web.py:1392
|
#: cps/web.py:1392
|
||||||
msgid "Update done"
|
msgid "Update done"
|
||||||
msgstr ""
|
msgstr "Actualización realizada"
|
||||||
|
|
||||||
#: cps/web.py:1470 cps/web.py:1483
|
#: cps/web.py:1470 cps/web.py:1483
|
||||||
msgid "search"
|
msgid "search"
|
||||||
msgstr ""
|
msgstr "búsqueda"
|
||||||
|
|
||||||
#: cps/web.py:1602 cps/web.py:1609 cps/web.py:1616 cps/web.py:1623
|
#: cps/web.py:1602 cps/web.py:1609 cps/web.py:1616 cps/web.py:1623
|
||||||
msgid "Read a Book"
|
msgid "Read a Book"
|
||||||
msgstr "Leer un Libro"
|
msgstr "Leer un libro"
|
||||||
|
|
||||||
#: cps/web.py:1676 cps/web.py:2152
|
#: cps/web.py:1676 cps/web.py:2152
|
||||||
msgid "Please fill out all fields!"
|
msgid "Please fill out all fields!"
|
||||||
msgstr "Por favor llenar todos los campos!"
|
msgstr "¡Por favor completar todos los campos!"
|
||||||
|
|
||||||
#: cps/web.py:1677 cps/web.py:1693 cps/web.py:1698 cps/web.py:1700
|
#: cps/web.py:1677 cps/web.py:1693 cps/web.py:1698 cps/web.py:1700
|
||||||
msgid "register"
|
msgid "register"
|
||||||
msgstr "Registrarse"
|
msgstr "registrarse"
|
||||||
|
|
||||||
#: cps/web.py:1692
|
#: cps/web.py:1692
|
||||||
msgid "An unknown error occured. Please try again later."
|
msgid "An unknown error occured. Please try again later."
|
||||||
msgstr "Ocurrio un error. Intentar de nuevo mas tarde."
|
msgstr "Error desconocido. Por favor, inténtelo de nuevo mas tarde."
|
||||||
|
|
||||||
#: cps/web.py:1697
|
#: cps/web.py:1697
|
||||||
msgid "This username or email address is already in use."
|
msgid "This username or email address is already in use."
|
||||||
msgstr "Usuario o direccion de correo en uso."
|
msgstr "Usuario o dirección de correo en uso."
|
||||||
|
|
||||||
#: cps/web.py:1715
|
#: cps/web.py:1715
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -194,7 +195,7 @@ msgstr "Usuario o contraseña invalido"
|
|||||||
|
|
||||||
#: cps/web.py:1722
|
#: cps/web.py:1722
|
||||||
msgid "login"
|
msgid "login"
|
||||||
msgstr "Iniciar Sesion"
|
msgstr "Iniciar sesión"
|
||||||
|
|
||||||
#: cps/web.py:1739
|
#: cps/web.py:1739
|
||||||
msgid "Please configure the SMTP mail settings first..."
|
msgid "Please configure the SMTP mail settings first..."
|
||||||
@ -236,20 +237,20 @@ msgstr "Estante %(title)s creado"
|
|||||||
|
|
||||||
#: cps/web.py:1819 cps/web.py:1847
|
#: cps/web.py:1819 cps/web.py:1847
|
||||||
msgid "There was an error"
|
msgid "There was an error"
|
||||||
msgstr "Hemos tenido un error"
|
msgstr "Ha sucedido un error"
|
||||||
|
|
||||||
#: cps/web.py:1820 cps/web.py:1822
|
#: cps/web.py:1820 cps/web.py:1822
|
||||||
msgid "create a shelf"
|
msgid "create a shelf"
|
||||||
msgstr "Crear un Estante"
|
msgstr "crear un estante"
|
||||||
|
|
||||||
#: cps/web.py:1845
|
#: cps/web.py:1845
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Shelf %(title)s changed"
|
msgid "Shelf %(title)s changed"
|
||||||
msgstr ""
|
msgstr "Estante %(title)s cambiado"
|
||||||
|
|
||||||
#: cps/web.py:1848 cps/web.py:1850
|
#: cps/web.py:1848 cps/web.py:1850
|
||||||
msgid "Edit a shelf"
|
msgid "Edit a shelf"
|
||||||
msgstr ""
|
msgstr "Editar un estante"
|
||||||
|
|
||||||
#: cps/web.py:1868
|
#: cps/web.py:1868
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -264,11 +265,11 @@ msgstr "Estante: '%(name)s'"
|
|||||||
#: cps/web.py:1921
|
#: cps/web.py:1921
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Change order of Shelf: '%(name)s'"
|
msgid "Change order of Shelf: '%(name)s'"
|
||||||
msgstr ""
|
msgstr "Cambiar orden del estante: '%(name)s'"
|
||||||
|
|
||||||
#: cps/web.py:1985
|
#: cps/web.py:1985
|
||||||
msgid "Found an existing account for this email address."
|
msgid "Found an existing account for this email address."
|
||||||
msgstr "Existe una cuenta vinculada a esta cuenta de correo."
|
msgstr "Existe una cuenta vinculada a esta dirección de correo."
|
||||||
|
|
||||||
#: cps/web.py:1987 cps/web.py:1991
|
#: cps/web.py:1987 cps/web.py:1991
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -281,19 +282,19 @@ msgstr "Perfil actualizado"
|
|||||||
|
|
||||||
#: cps/web.py:2002
|
#: cps/web.py:2002
|
||||||
msgid "Admin page"
|
msgid "Admin page"
|
||||||
msgstr ""
|
msgstr "Página de administración"
|
||||||
|
|
||||||
#: cps/web.py:2106
|
#: cps/web.py:2106
|
||||||
msgid "Calibre-web configuration updated"
|
msgid "Calibre-web configuration updated"
|
||||||
msgstr ""
|
msgstr "Configuración de Calibre-web actualizada"
|
||||||
|
|
||||||
#: cps/web.py:2113 cps/web.py:2119 cps/web.py:2133
|
#: cps/web.py:2113 cps/web.py:2119 cps/web.py:2133
|
||||||
msgid "Basic Configuration"
|
msgid "Basic Configuration"
|
||||||
msgstr ""
|
msgstr "Configuración básica"
|
||||||
|
|
||||||
#: cps/web.py:2117
|
#: cps/web.py:2117
|
||||||
msgid "DB location is not valid, please enter correct path"
|
msgid "DB location is not valid, please enter correct path"
|
||||||
msgstr ""
|
msgstr "Localicación de la BD inválida. Por favor, introduzca la ruta correcta."
|
||||||
|
|
||||||
#: cps/templates/admin.html:34 cps/web.py:2154 cps/web.py:2202
|
#: cps/templates/admin.html:34 cps/web.py:2154 cps/web.py:2202
|
||||||
msgid "Add new user"
|
msgid "Add new user"
|
||||||
@ -306,11 +307,11 @@ msgstr "Usuario '%(user)s' creado"
|
|||||||
|
|
||||||
#: 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 "Se ha encontrado una cuenta vinculada a esta cuenta de correo o usuario."
|
msgstr "Se ha encontrado una cuenta vinculada a esta dirección de correo o nombre de usuario."
|
||||||
|
|
||||||
#: cps/web.py:2220
|
#: cps/web.py:2220
|
||||||
msgid "Mail settings updated"
|
msgid "Mail settings updated"
|
||||||
msgstr "Parametros de correo actualizados"
|
msgstr "Parámetros de correo actualizados"
|
||||||
|
|
||||||
#: cps/web.py:2227
|
#: cps/web.py:2227
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -324,7 +325,7 @@ msgstr "Error al realizar envio de prueba a E-Mail: %(res)s"
|
|||||||
|
|
||||||
#: cps/web.py:2234
|
#: cps/web.py:2234
|
||||||
msgid "E-Mail settings updated"
|
msgid "E-Mail settings updated"
|
||||||
msgstr ""
|
msgstr "Ajustes de correo electrónico actualizados"
|
||||||
|
|
||||||
#: cps/web.py:2235
|
#: cps/web.py:2235
|
||||||
msgid "Edit mail settings"
|
msgid "Edit mail settings"
|
||||||
@ -338,11 +339,11 @@ msgstr "Usuario '%(nick)s' borrado"
|
|||||||
#: cps/web.py:2349
|
#: cps/web.py:2349
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "User '%(nick)s' updated"
|
msgid "User '%(nick)s' updated"
|
||||||
msgstr "Usuario '%(nick)s' Actualizado"
|
msgstr "Usuario '%(nick)s' actualizado"
|
||||||
|
|
||||||
#: cps/web.py:2352
|
#: cps/web.py:2352
|
||||||
msgid "An unknown error occured."
|
msgid "An unknown error occured."
|
||||||
msgstr "Oups ! Error inesperado."
|
msgstr "Error inesperado."
|
||||||
|
|
||||||
#: cps/web.py:2355
|
#: cps/web.py:2355
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -351,16 +352,16 @@ msgstr "Editar Usuario %(nick)s"
|
|||||||
|
|
||||||
#: cps/web.py:2574 cps/web.py:2577 cps/web.py:2689
|
#: cps/web.py:2574 cps/web.py:2577 cps/web.py:2689
|
||||||
msgid "edit metadata"
|
msgid "edit metadata"
|
||||||
msgstr ""
|
msgstr "editar metainformación"
|
||||||
|
|
||||||
#: cps/web.py:2598
|
#: cps/web.py:2598
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "File extension \"%s\" is not allowed to be uploaded to this server"
|
msgid "File extension \"%s\" is not allowed to be uploaded to this server"
|
||||||
msgstr ""
|
msgstr "No se permite subir archivos con la extensión \"%s\" a este servidor"
|
||||||
|
|
||||||
#: cps/web.py:2604
|
#: cps/web.py:2604
|
||||||
msgid "File to be uploaded must have an extension"
|
msgid "File to be uploaded must have an extension"
|
||||||
msgstr ""
|
msgstr "El archivo a subir debe tener una extensión"
|
||||||
|
|
||||||
#: cps/web.py:2621
|
#: cps/web.py:2621
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -399,7 +400,7 @@ msgstr "DLS"
|
|||||||
|
|
||||||
#: cps/templates/admin.html:12 cps/templates/layout.html:85
|
#: cps/templates/admin.html:12 cps/templates/layout.html:85
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Administracion"
|
msgstr "Administración"
|
||||||
|
|
||||||
#: cps/templates/admin.html:13 cps/templates/detail.html:134
|
#: cps/templates/admin.html:13 cps/templates/detail.html:134
|
||||||
msgid "Download"
|
msgid "Download"
|
||||||
@ -419,7 +420,7 @@ msgstr "Clave"
|
|||||||
|
|
||||||
#: cps/templates/admin.html:35
|
#: cps/templates/admin.html:35
|
||||||
msgid "SMTP mail settings"
|
msgid "SMTP mail settings"
|
||||||
msgstr "Parametros smtp del correo"
|
msgstr "Parámetros smtp del correo"
|
||||||
|
|
||||||
#: cps/templates/admin.html:38 cps/templates/email_edit.html:7
|
#: cps/templates/admin.html:38 cps/templates/email_edit.html:7
|
||||||
msgid "SMTP hostname"
|
msgid "SMTP hostname"
|
||||||
@ -451,76 +452,76 @@ msgstr "Cambiar parametros smtp"
|
|||||||
|
|
||||||
#: cps/templates/admin.html:57 cps/templates/admin.html:77
|
#: cps/templates/admin.html:57 cps/templates/admin.html:77
|
||||||
msgid "Configuration"
|
msgid "Configuration"
|
||||||
msgstr ""
|
msgstr "Configuración"
|
||||||
|
|
||||||
#: cps/templates/admin.html:60
|
#: cps/templates/admin.html:60
|
||||||
msgid "Calibre DB dir"
|
msgid "Calibre DB dir"
|
||||||
msgstr ""
|
msgstr "Dir DB Calibre"
|
||||||
|
|
||||||
#: cps/templates/admin.html:61 cps/templates/config_edit.html:76
|
#: cps/templates/admin.html:61 cps/templates/config_edit.html:76
|
||||||
msgid "Log Level"
|
msgid "Log Level"
|
||||||
msgstr ""
|
msgstr "Nivel de registro"
|
||||||
|
|
||||||
#: cps/templates/admin.html:62
|
#: cps/templates/admin.html:62
|
||||||
msgid "Port"
|
msgid "Port"
|
||||||
msgstr ""
|
msgstr "Puerto"
|
||||||
|
|
||||||
#: cps/templates/admin.html:63 cps/templates/config_edit.html:60
|
#: cps/templates/admin.html:63 cps/templates/config_edit.html:60
|
||||||
msgid "Books per page"
|
msgid "Books per page"
|
||||||
msgstr ""
|
msgstr "Libros por página"
|
||||||
|
|
||||||
#: cps/templates/admin.html:64
|
#: cps/templates/admin.html:64
|
||||||
msgid "Uploading"
|
msgid "Uploading"
|
||||||
msgstr ""
|
msgstr "Subiendo"
|
||||||
|
|
||||||
#: cps/templates/admin.html:65
|
#: cps/templates/admin.html:65
|
||||||
msgid "Public registration"
|
msgid "Public registration"
|
||||||
msgstr ""
|
msgstr "Registro público"
|
||||||
|
|
||||||
#: cps/templates/admin.html:66
|
#: cps/templates/admin.html:66
|
||||||
msgid "Anonymous browsing"
|
msgid "Anonymous browsing"
|
||||||
msgstr ""
|
msgstr "Navegación anónima"
|
||||||
|
|
||||||
#: cps/templates/admin.html:78
|
#: cps/templates/admin.html:78
|
||||||
msgid "Administration"
|
msgid "Administration"
|
||||||
msgstr ""
|
msgstr "Administración"
|
||||||
|
|
||||||
#: cps/templates/admin.html:80
|
#: cps/templates/admin.html:80
|
||||||
msgid "Current commit timestamp"
|
msgid "Current commit timestamp"
|
||||||
msgstr ""
|
msgstr "Marca temporal del commit actual"
|
||||||
|
|
||||||
#: cps/templates/admin.html:81
|
#: cps/templates/admin.html:81
|
||||||
msgid "Newest commit timestamp"
|
msgid "Newest commit timestamp"
|
||||||
msgstr ""
|
msgstr "Marca temporal del commit más reciente"
|
||||||
|
|
||||||
#: cps/templates/admin.html:83
|
#: cps/templates/admin.html:83
|
||||||
msgid "Reconnect to Calibre DB"
|
msgid "Reconnect to Calibre DB"
|
||||||
msgstr ""
|
msgstr "Reconectar la BD Calibre"
|
||||||
|
|
||||||
#: cps/templates/admin.html:84
|
#: cps/templates/admin.html:84
|
||||||
msgid "Restart Calibre-web"
|
msgid "Restart Calibre-web"
|
||||||
msgstr ""
|
msgstr "Reinicial Calibre-web"
|
||||||
|
|
||||||
#: cps/templates/admin.html:85
|
#: cps/templates/admin.html:85
|
||||||
msgid "Stop Calibre-web"
|
msgid "Stop Calibre-web"
|
||||||
msgstr ""
|
msgstr "Detener Calibre-web"
|
||||||
|
|
||||||
#: cps/templates/admin.html:86
|
#: cps/templates/admin.html:86
|
||||||
msgid "Check for update"
|
msgid "Check for update"
|
||||||
msgstr ""
|
msgstr "Buscar actualizaciones"
|
||||||
|
|
||||||
#: cps/templates/admin.html:87
|
#: cps/templates/admin.html:87
|
||||||
msgid "Perform Update"
|
msgid "Perform Update"
|
||||||
msgstr ""
|
msgstr "Actualizar"
|
||||||
|
|
||||||
#: cps/templates/admin.html:97
|
#: cps/templates/admin.html:97
|
||||||
msgid "Do you really want to restart Calibre-web?"
|
msgid "Do you really want to restart Calibre-web?"
|
||||||
msgstr ""
|
msgstr "¿Seguro que quiere reiniciar Calibre-web?"
|
||||||
|
|
||||||
#: cps/templates/admin.html:102 cps/templates/admin.html:116
|
#: cps/templates/admin.html:102 cps/templates/admin.html:116
|
||||||
#: cps/templates/admin.html:137
|
#: cps/templates/admin.html:137
|
||||||
msgid "Ok"
|
msgid "Ok"
|
||||||
msgstr ""
|
msgstr "Ok"
|
||||||
|
|
||||||
#: cps/templates/admin.html:103 cps/templates/admin.html:117
|
#: cps/templates/admin.html:103 cps/templates/admin.html:117
|
||||||
#: cps/templates/book_edit.html:109 cps/templates/config_edit.html:119
|
#: cps/templates/book_edit.html:109 cps/templates/config_edit.html:119
|
||||||
@ -531,11 +532,11 @@ msgstr "Regresar"
|
|||||||
|
|
||||||
#: cps/templates/admin.html:115
|
#: cps/templates/admin.html:115
|
||||||
msgid "Do you really want to stop Calibre-web?"
|
msgid "Do you really want to stop Calibre-web?"
|
||||||
msgstr ""
|
msgstr "¿Seguro que quiere detener Calibre-web?"
|
||||||
|
|
||||||
#: cps/templates/admin.html:128
|
#: cps/templates/admin.html:128
|
||||||
msgid "Updating, please do not reload page"
|
msgid "Updating, please do not reload page"
|
||||||
msgstr ""
|
msgstr "Actualizando. Por favor, no recargue la página."
|
||||||
|
|
||||||
#: cps/templates/book_edit.html:16 cps/templates/search_form.html:6
|
#: cps/templates/book_edit.html:16 cps/templates/search_form.html:6
|
||||||
msgid "Book Title"
|
msgid "Book Title"
|
||||||
@ -589,7 +590,7 @@ msgstr "Ver libro tras la edicion"
|
|||||||
|
|
||||||
#: 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 "Obtener metainformación"
|
||||||
|
|
||||||
#: 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
|
||||||
@ -599,76 +600,76 @@ msgstr "Enviar"
|
|||||||
|
|
||||||
#: cps/templates/book_edit.html:121
|
#: cps/templates/book_edit.html:121
|
||||||
msgid "Keyword"
|
msgid "Keyword"
|
||||||
msgstr ""
|
msgstr "Palabra clave"
|
||||||
|
|
||||||
#: cps/templates/book_edit.html:122
|
#: cps/templates/book_edit.html:122
|
||||||
msgid " Search keyword "
|
msgid " Search keyword "
|
||||||
msgstr ""
|
msgstr "Buscar palabras clave"
|
||||||
|
|
||||||
#: 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!"
|
||||||
msgstr "Vamos!"
|
msgstr "¡Vamos!"
|
||||||
|
|
||||||
#: 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 "Haga clic en la portada para cargar la metainformación en el formulario"
|
||||||
|
|
||||||
#: 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 "Cargando..."
|
||||||
|
|
||||||
#: cps/templates/book_edit.html:132
|
#: cps/templates/book_edit.html:132
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr ""
|
msgstr "Cerrar"
|
||||||
|
|
||||||
#: cps/templates/book_edit.html:143
|
#: cps/templates/book_edit.html:143
|
||||||
msgid "Search error!"
|
msgid "Search error!"
|
||||||
msgstr ""
|
msgstr "¡Error en la búsqueda!"
|
||||||
|
|
||||||
#: 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 "¡Sin resultados! Por favor, pruebe otra palabra clave."
|
||||||
|
|
||||||
#: 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 "Editor"
|
||||||
|
|
||||||
#: cps/templates/book_edit.html:148
|
#: cps/templates/book_edit.html:148
|
||||||
msgid "Source"
|
msgid "Source"
|
||||||
msgstr ""
|
msgstr "Origen"
|
||||||
|
|
||||||
#: cps/templates/config_edit.html:7
|
#: cps/templates/config_edit.html:7
|
||||||
msgid "Location of Calibre database"
|
msgid "Location of Calibre database"
|
||||||
msgstr ""
|
msgstr "Ubicación de la base de datos Calibre"
|
||||||
|
|
||||||
#: cps/templates/config_edit.html:13
|
#: cps/templates/config_edit.html:13
|
||||||
msgid "Use google drive?"
|
msgid "Use google drive?"
|
||||||
msgstr ""
|
msgstr "¿Utiliza google drive?"
|
||||||
|
|
||||||
#: cps/templates/config_edit.html:17
|
#: cps/templates/config_edit.html:17
|
||||||
msgid "Client id"
|
msgid "Client id"
|
||||||
msgstr ""
|
msgstr "Id cliente"
|
||||||
|
|
||||||
#: cps/templates/config_edit.html:21
|
#: cps/templates/config_edit.html:21
|
||||||
msgid "Client secret"
|
msgid "Client secret"
|
||||||
msgstr ""
|
msgstr "Contraseña cliente"
|
||||||
|
|
||||||
#: cps/templates/config_edit.html:25
|
#: cps/templates/config_edit.html:25
|
||||||
msgid "Calibre Base URL"
|
msgid "Calibre Base URL"
|
||||||
msgstr ""
|
msgstr "URL Base de Calibre"
|
||||||
|
|
||||||
#: cps/templates/config_edit.html:29
|
#: cps/templates/config_edit.html:29
|
||||||
msgid "Google drive Calibre folder"
|
msgid "Google drive Calibre folder"
|
||||||
msgstr ""
|
msgstr "Carpeta Calibre de Google drive"
|
||||||
|
|
||||||
#: cps/templates/config_edit.html:38
|
#: cps/templates/config_edit.html:38
|
||||||
msgid "Metadata Watch Channel ID"
|
msgid "Metadata Watch Channel ID"
|
||||||
msgstr ""
|
msgstr "Metadata Watch Channel ID"
|
||||||
|
|
||||||
#: cps/templates/config_edit.html:52
|
#: cps/templates/config_edit.html:52
|
||||||
msgid "Server Port"
|
msgid "Server Port"
|
||||||
msgstr ""
|
msgstr "Puerto del servidor"
|
||||||
|
|
||||||
#: cps/templates/config_edit.html:56 cps/templates/shelf_edit.html:7
|
#: cps/templates/config_edit.html:56 cps/templates/shelf_edit.html:7
|
||||||
msgid "Title"
|
msgid "Title"
|
||||||
@ -676,31 +677,31 @@ msgstr "Titulo"
|
|||||||
|
|
||||||
#: cps/templates/config_edit.html:64
|
#: cps/templates/config_edit.html:64
|
||||||
msgid "No. of random books to show"
|
msgid "No. of random books to show"
|
||||||
msgstr ""
|
msgstr "Número de libros aletorios a mostrar"
|
||||||
|
|
||||||
#: cps/templates/config_edit.html:68
|
#: cps/templates/config_edit.html:68
|
||||||
msgid "Regular expression for ignoring columns"
|
msgid "Regular expression for ignoring columns"
|
||||||
msgstr ""
|
msgstr "Expresión regular para ignorar columnas"
|
||||||
|
|
||||||
#: cps/templates/config_edit.html:72
|
#: cps/templates/config_edit.html:72
|
||||||
msgid "Regular expression for title sorting"
|
msgid "Regular expression for title sorting"
|
||||||
msgstr ""
|
msgstr "Expresión regular para ordenar títulos"
|
||||||
|
|
||||||
#: cps/templates/config_edit.html:86
|
#: cps/templates/config_edit.html:86
|
||||||
msgid "Enable uploading"
|
msgid "Enable uploading"
|
||||||
msgstr ""
|
msgstr "Permitir subida"
|
||||||
|
|
||||||
#: cps/templates/config_edit.html:90
|
#: cps/templates/config_edit.html:90
|
||||||
msgid "Enable anonymous browsing"
|
msgid "Enable anonymous browsing"
|
||||||
msgstr ""
|
msgstr "Permitir navegación anónima"
|
||||||
|
|
||||||
#: cps/templates/config_edit.html:94
|
#: cps/templates/config_edit.html:94
|
||||||
msgid "Enable public registration"
|
msgid "Enable public registration"
|
||||||
msgstr ""
|
msgstr "Permitir registro público"
|
||||||
|
|
||||||
#: cps/templates/config_edit.html:96
|
#: cps/templates/config_edit.html:96
|
||||||
msgid "Default Settings for new users"
|
msgid "Default Settings for new users"
|
||||||
msgstr ""
|
msgstr "Ajustes por defecto para nuevos usuarios"
|
||||||
|
|
||||||
#: cps/templates/config_edit.html:99 cps/templates/user_edit.html:87
|
#: cps/templates/config_edit.html:99 cps/templates/user_edit.html:87
|
||||||
msgid "Admin user"
|
msgid "Admin user"
|
||||||
@ -741,11 +742,11 @@ msgstr "Lenguaje"
|
|||||||
|
|
||||||
#: cps/templates/detail.html:81
|
#: cps/templates/detail.html:81
|
||||||
msgid "Publishing date"
|
msgid "Publishing date"
|
||||||
msgstr ""
|
msgstr "Fecha de publicación"
|
||||||
|
|
||||||
#: cps/templates/detail.html:115
|
#: cps/templates/detail.html:115
|
||||||
msgid "Read"
|
msgid "Read"
|
||||||
msgstr ""
|
msgstr "Leer"
|
||||||
|
|
||||||
#: cps/templates/detail.html:123
|
#: cps/templates/detail.html:123
|
||||||
msgid "Description:"
|
msgid "Description:"
|
||||||
@ -765,23 +766,23 @@ msgstr "Editar la metadata"
|
|||||||
|
|
||||||
#: cps/templates/email_edit.html:11
|
#: cps/templates/email_edit.html:11
|
||||||
msgid "SMTP port (usually 25 for plain SMTP and 465 for SSL and 587 for STARTTLS)"
|
msgid "SMTP port (usually 25 for plain SMTP and 465 for SSL and 587 for STARTTLS)"
|
||||||
msgstr ""
|
msgstr "Puerto SMTP (por lo general 25 para SMTP plano, 465 para SSL y 587 para STARTTLS)"
|
||||||
|
|
||||||
#: cps/templates/email_edit.html:15
|
#: cps/templates/email_edit.html:15
|
||||||
msgid "Encryption"
|
msgid "Encryption"
|
||||||
msgstr ""
|
msgstr "Cifrado"
|
||||||
|
|
||||||
#: cps/templates/email_edit.html:17
|
#: cps/templates/email_edit.html:17
|
||||||
msgid "None"
|
msgid "None"
|
||||||
msgstr ""
|
msgstr "Ninguno"
|
||||||
|
|
||||||
#: cps/templates/email_edit.html:18
|
#: cps/templates/email_edit.html:18
|
||||||
msgid "STARTTLS"
|
msgid "STARTTLS"
|
||||||
msgstr ""
|
msgstr "STATRTTLS"
|
||||||
|
|
||||||
#: cps/templates/email_edit.html:19
|
#: cps/templates/email_edit.html:19
|
||||||
msgid "SSL/TLS"
|
msgid "SSL/TLS"
|
||||||
msgstr ""
|
msgstr "SSL/TLS"
|
||||||
|
|
||||||
#: cps/templates/email_edit.html:31
|
#: cps/templates/email_edit.html:31
|
||||||
msgid "From e-mail"
|
msgid "From e-mail"
|
||||||
@ -817,11 +818,11 @@ msgstr "Libros Populares"
|
|||||||
|
|
||||||
#: cps/templates/index.xml:19
|
#: cps/templates/index.xml:19
|
||||||
msgid "Popular publications from this catalog based on Downloads."
|
msgid "Popular publications from this catalog based on Downloads."
|
||||||
msgstr ""
|
msgstr "Publicaciones mas populares para este catálogo basadas en las descargas."
|
||||||
|
|
||||||
#: cps/templates/index.xml:22 cps/templates/layout.html:129
|
#: cps/templates/index.xml:22 cps/templates/layout.html:129
|
||||||
msgid "Best rated Books"
|
msgid "Best rated Books"
|
||||||
msgstr ""
|
msgstr "Libros mejor valorados"
|
||||||
|
|
||||||
#: cps/templates/index.xml:26
|
#: cps/templates/index.xml:26
|
||||||
msgid "Popular publications from this catalog based on Rating."
|
msgid "Popular publications from this catalog based on Rating."
|
||||||
@ -829,11 +830,11 @@ msgstr "Publicaciones populares del catalogo basados en el puntaje."
|
|||||||
|
|
||||||
#: cps/templates/index.xml:29 cps/templates/layout.html:124
|
#: cps/templates/index.xml:29 cps/templates/layout.html:124
|
||||||
msgid "New Books"
|
msgid "New Books"
|
||||||
msgstr "Nuevos Libros"
|
msgstr "Nuevos libros"
|
||||||
|
|
||||||
#: cps/templates/index.xml:33
|
#: cps/templates/index.xml:33
|
||||||
msgid "The latest Books"
|
msgid "The latest Books"
|
||||||
msgstr "Libros Recientes"
|
msgstr "Libros recientes"
|
||||||
|
|
||||||
#: cps/templates/index.xml:40
|
#: cps/templates/index.xml:40
|
||||||
msgid "Show Random Books"
|
msgid "Show Random Books"
|
||||||
@ -842,12 +843,12 @@ msgstr "Mostrar libros al azar"
|
|||||||
#: 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 "Libros leídos"
|
||||||
|
|
||||||
#: 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 "Libros no leídos"
|
||||||
|
|
||||||
#: cps/templates/index.xml:57 cps/templates/layout.html:144
|
#: cps/templates/index.xml:57 cps/templates/layout.html:144
|
||||||
msgid "Authors"
|
msgid "Authors"
|
||||||
@ -867,7 +868,7 @@ msgstr "Libros ordenados por Series"
|
|||||||
|
|
||||||
#: cps/templates/layout.html:48
|
#: cps/templates/layout.html:48
|
||||||
msgid "Toggle navigation"
|
msgid "Toggle navigation"
|
||||||
msgstr ""
|
msgstr "Alternar navegación"
|
||||||
|
|
||||||
#: cps/templates/layout.html:68
|
#: cps/templates/layout.html:68
|
||||||
msgid "Advanced Search"
|
msgid "Advanced Search"
|
||||||
@ -875,7 +876,7 @@ msgstr "Busqueda avanzada"
|
|||||||
|
|
||||||
#: cps/templates/layout.html:89
|
#: cps/templates/layout.html:89
|
||||||
msgid "Logout"
|
msgid "Logout"
|
||||||
msgstr "Cerrar Sesion"
|
msgstr "Cerrar sesión"
|
||||||
|
|
||||||
#: cps/templates/layout.html:94 cps/templates/register.html:18
|
#: cps/templates/layout.html:94 cps/templates/register.html:18
|
||||||
msgid "Register"
|
msgid "Register"
|
||||||
@ -899,11 +900,11 @@ msgstr "Lenguaje"
|
|||||||
|
|
||||||
#: cps/templates/layout.html:149
|
#: cps/templates/layout.html:149
|
||||||
msgid "Public Shelves"
|
msgid "Public Shelves"
|
||||||
msgstr "Estantes Publicos"
|
msgstr "Estantes públicos"
|
||||||
|
|
||||||
#: cps/templates/layout.html:153
|
#: cps/templates/layout.html:153
|
||||||
msgid "Your Shelves"
|
msgid "Your Shelves"
|
||||||
msgstr "Sus Estantes"
|
msgstr "Sus estantes"
|
||||||
|
|
||||||
#: cps/templates/layout.html:158
|
#: cps/templates/layout.html:158
|
||||||
msgid "Create a Shelf"
|
msgid "Create a Shelf"
|
||||||
@ -929,7 +930,7 @@ msgstr "Recordarme"
|
|||||||
|
|
||||||
#: cps/templates/osd.xml:5
|
#: cps/templates/osd.xml:5
|
||||||
msgid "Calibre Web ebook catalog"
|
msgid "Calibre Web ebook catalog"
|
||||||
msgstr ""
|
msgstr "Catálogo de libros electrónicos Calibre Web"
|
||||||
|
|
||||||
#: cps/templates/read.html:136
|
#: cps/templates/read.html:136
|
||||||
msgid "Reflow text when sidebars are open."
|
msgid "Reflow text when sidebars are open."
|
||||||
@ -941,7 +942,7 @@ msgstr "Visor PDF.js"
|
|||||||
|
|
||||||
#: cps/templates/readtxt.html:6
|
#: cps/templates/readtxt.html:6
|
||||||
msgid "Basic txt Reader"
|
msgid "Basic txt Reader"
|
||||||
msgstr ""
|
msgstr "Lector básico de txt"
|
||||||
|
|
||||||
#: cps/templates/register.html:4
|
#: cps/templates/register.html:4
|
||||||
msgid "Register a new account"
|
msgid "Register a new account"
|
||||||
@ -981,11 +982,11 @@ msgstr "Excluir etiquetas"
|
|||||||
|
|
||||||
#: cps/templates/search_form.html:47
|
#: cps/templates/search_form.html:47
|
||||||
msgid "Exclude Series"
|
msgid "Exclude Series"
|
||||||
msgstr ""
|
msgstr "Excluir series"
|
||||||
|
|
||||||
#: cps/templates/search_form.html:68
|
#: cps/templates/search_form.html:68
|
||||||
msgid "Exclude Languages"
|
msgid "Exclude Languages"
|
||||||
msgstr ""
|
msgstr "Excluir idiomas"
|
||||||
|
|
||||||
#: cps/templates/shelf.html:6
|
#: cps/templates/shelf.html:6
|
||||||
msgid "Delete this Shelf"
|
msgid "Delete this Shelf"
|
||||||
@ -997,15 +998,15 @@ msgstr "Editar nombre del estante"
|
|||||||
|
|
||||||
#: cps/templates/shelf.html:8 cps/templates/shelf_order.html:11
|
#: cps/templates/shelf.html:8 cps/templates/shelf_order.html:11
|
||||||
msgid "Change order"
|
msgid "Change order"
|
||||||
msgstr ""
|
msgstr "Cambiar orden"
|
||||||
|
|
||||||
#: cps/templates/shelf_edit.html:12
|
#: cps/templates/shelf_edit.html:12
|
||||||
msgid "should the shelf be public?"
|
msgid "should the shelf be public?"
|
||||||
msgstr "Debe ser el estante publico?"
|
msgstr "¿Hacer público el estante?"
|
||||||
|
|
||||||
#: cps/templates/shelf_order.html:5
|
#: cps/templates/shelf_order.html:5
|
||||||
msgid "Drag 'n drop to rearrange order"
|
msgid "Drag 'n drop to rearrange order"
|
||||||
msgstr ""
|
msgstr "Pinchar y arrastrar para reordenar"
|
||||||
|
|
||||||
#: cps/templates/stats.html:3
|
#: cps/templates/stats.html:3
|
||||||
msgid "Calibre library statistics"
|
msgid "Calibre library statistics"
|
||||||
@ -1021,11 +1022,11 @@ msgstr "Autores en esta Biblioteca"
|
|||||||
|
|
||||||
#: cps/templates/stats.html:16
|
#: cps/templates/stats.html:16
|
||||||
msgid "Categories in this Library"
|
msgid "Categories in this Library"
|
||||||
msgstr ""
|
msgstr "Categorías en esta librería"
|
||||||
|
|
||||||
#: cps/templates/stats.html:20
|
#: cps/templates/stats.html:20
|
||||||
msgid "Series in this Library"
|
msgid "Series in this Library"
|
||||||
msgstr ""
|
msgstr "Series en esta librería"
|
||||||
|
|
||||||
#: cps/templates/stats.html:24
|
#: cps/templates/stats.html:24
|
||||||
msgid "Linked libraries"
|
msgid "Linked libraries"
|
||||||
@ -1061,7 +1062,7 @@ msgstr "Mostrar libros populares"
|
|||||||
|
|
||||||
#: cps/templates/user_edit.html:55
|
#: cps/templates/user_edit.html:55
|
||||||
msgid "Show best rated books"
|
msgid "Show best rated books"
|
||||||
msgstr ""
|
msgstr "Mostrar libros mejor valorados"
|
||||||
|
|
||||||
#: cps/templates/user_edit.html:59
|
#: cps/templates/user_edit.html:59
|
||||||
msgid "Show language selection"
|
msgid "Show language selection"
|
||||||
@ -1077,15 +1078,15 @@ msgstr "Mostrar categorias elegidas"
|
|||||||
|
|
||||||
#: cps/templates/user_edit.html:71
|
#: cps/templates/user_edit.html:71
|
||||||
msgid "Show author selection"
|
msgid "Show author selection"
|
||||||
msgstr ""
|
msgstr "Mostrar selección de autores"
|
||||||
|
|
||||||
#: cps/templates/user_edit.html:75
|
#: cps/templates/user_edit.html:75
|
||||||
msgid "Show read and unread"
|
msgid "Show read and unread"
|
||||||
msgstr ""
|
msgstr "Mostrar leídos y no leídos"
|
||||||
|
|
||||||
#: 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"
|
||||||
msgstr ""
|
msgstr "Mostrar libro aleatorios con vista detallada"
|
||||||
|
|
||||||
#: cps/templates/user_edit.html:112
|
#: cps/templates/user_edit.html:112
|
||||||
msgid "Delete this user"
|
msgid "Delete this user"
|
||||||
@ -31922,4 +31923,3 @@ msgstr "Zaza"
|
|||||||
#. name for zzj
|
#. name for zzj
|
||||||
msgid "Zhuang; Zuojiang"
|
msgid "Zhuang; Zuojiang"
|
||||||
msgstr "Chuang zuojiang"
|
msgstr "Chuang zuojiang"
|
||||||
|
|
||||||
|
Binary file not shown.
@ -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 "最新提交时间戳"
|
|||||||
|
|
||||||
#: 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 "编辑后查看书籍"
|
|||||||
|
|
||||||
#: 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 "提交"
|
|||||||
|
|
||||||
#: 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 "走起!"
|
|||||||
|
|
||||||
#: 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 数据库位置"
|
|||||||
|
|
||||||
#: 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"
|
|||||||
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 "显示随机书籍"
|
|||||||
#: 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 "显示作者选择"
|
|||||||
|
|
||||||
#: 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"
|
||||||
|
66
cps/ub.py
66
cps/ub.py
@ -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:
|
|||||||
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:
|
|||||||
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:
|
|||||||
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:
|
|||||||
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():
|
|||||||
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():
|
|||||||
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
|
||||||
|
381
cps/web.py
381
cps/web.py
@ -32,6 +32,7 @@ from flask_babel import gettext as _
|
|||||||
import requests
|
import requests
|
||||||
import zipfile
|
import zipfile
|
||||||
from werkzeug.security import generate_password_hash, check_password_hash
|
from werkzeug.security import generate_password_hash, check_password_hash
|
||||||
|
from werkzeug.datastructures import Headers
|
||||||
from babel import Locale as LC
|
from babel import Locale as LC
|
||||||
from babel import negotiate_locale
|
from babel import negotiate_locale
|
||||||
from babel import __version__ as babelVersion
|
from babel import __version__ as babelVersion
|
||||||
@ -40,7 +41,6 @@ from functools import wraps
|
|||||||
import base64
|
import base64
|
||||||
from sqlalchemy.sql import *
|
from sqlalchemy.sql import *
|
||||||
import json
|
import json
|
||||||
import urllib
|
|
||||||
import datetime
|
import datetime
|
||||||
from iso639 import languages as isoLanguages
|
from iso639 import languages as isoLanguages
|
||||||
from iso639 import __version__ as iso639Version
|
from iso639 import __version__ as iso639Version
|
||||||
@ -53,24 +53,21 @@ import db
|
|||||||
from shutil import move, copyfile
|
from shutil import move, copyfile
|
||||||
from tornado.ioloop import IOLoop
|
from tornado.ioloop import IOLoop
|
||||||
import shutil
|
import shutil
|
||||||
import StringIO
|
|
||||||
import gdriveutils
|
import gdriveutils
|
||||||
import tempfile
|
import tempfile
|
||||||
import io
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import threading
|
|
||||||
|
|
||||||
from tornado import version as tornadoVersion
|
from tornado import version as tornadoVersion
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
from imp import reload
|
from imp import reload
|
||||||
except ImportError as e:
|
except ImportError:
|
||||||
from urllib import quote
|
from urllib import quote
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from flask_login import __version__ as flask_loginVersion
|
from flask_login import __version__ as flask_loginVersion
|
||||||
except ImportError as e:
|
except ImportError:
|
||||||
from flask_login.__about__ import __version__ as flask_loginVersion
|
from flask_login.__about__ import __version__ as flask_loginVersion
|
||||||
|
|
||||||
import time
|
import time
|
||||||
@ -82,7 +79,6 @@ try:
|
|||||||
use_generic_pdf_cover = False
|
use_generic_pdf_cover = False
|
||||||
except ImportError:
|
except ImportError:
|
||||||
use_generic_pdf_cover = True
|
use_generic_pdf_cover = True
|
||||||
from cgi import escape
|
|
||||||
|
|
||||||
# Global variables
|
# Global variables
|
||||||
gdrive_watch_callback_token='target=calibreweb-watch_files'
|
gdrive_watch_callback_token='target=calibreweb-watch_files'
|
||||||
@ -135,6 +131,7 @@ class Singleton:
|
|||||||
def __instancecheck__(self, inst):
|
def __instancecheck__(self, inst):
|
||||||
return isinstance(inst, self._decorated)
|
return isinstance(inst, self._decorated)
|
||||||
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class Gauth:
|
class Gauth:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -147,8 +144,8 @@ class Gdrive:
|
|||||||
|
|
||||||
class ReverseProxied(object):
|
class ReverseProxied(object):
|
||||||
"""Wrap the application in this middleware and configure the
|
"""Wrap the application in this middleware and configure the
|
||||||
front-end server to add these headers, to let you quietly bind
|
front-end server to add these headers, to let you quietly bind
|
||||||
this to a URL other than / and to an HTTP scheme that is
|
this to a URL other than / and to an HTTP scheme that is
|
||||||
different than what is used locally.
|
different than what is used locally.
|
||||||
|
|
||||||
Code courtesy of: http://flask.pocoo.org/snippets/35/
|
Code courtesy of: http://flask.pocoo.org/snippets/35/
|
||||||
@ -275,14 +272,9 @@ def load_user_from_header(header_val):
|
|||||||
return user
|
return user
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def check_auth(username, password):
|
def check_auth(username, password):
|
||||||
user = ub.session.query(ub.User).filter(ub.User.nickname == username).first()
|
user = ub.session.query(ub.User).filter(ub.User.nickname == username).first()
|
||||||
if user and check_password_hash(user.password, password):
|
return bool(user and check_password_hash(user.password, password))
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def authenticate():
|
def authenticate():
|
||||||
return Response(
|
return Response(
|
||||||
@ -389,7 +381,7 @@ def shortentitle_filter(s):
|
|||||||
def mimetype_filter(val):
|
def mimetype_filter(val):
|
||||||
try:
|
try:
|
||||||
s = mimetypes.types_map['.' + val]
|
s = mimetypes.types_map['.' + val]
|
||||||
except Exception as e:
|
except Exception:
|
||||||
s = 'application/octet-stream'
|
s = 'application/octet-stream'
|
||||||
return s
|
return s
|
||||||
|
|
||||||
@ -406,10 +398,10 @@ def timestamptodate(date, fmt=None):
|
|||||||
)
|
)
|
||||||
native = date.replace(tzinfo=None)
|
native = date.replace(tzinfo=None)
|
||||||
if fmt:
|
if fmt:
|
||||||
format=fmt
|
time_format=fmt
|
||||||
else:
|
else:
|
||||||
format='%d %m %Y - %H:%S'
|
time_format='%d %m %Y - %H:%S'
|
||||||
return native.strftime(format)
|
return native.strftime(time_format)
|
||||||
|
|
||||||
def admin_required(f):
|
def admin_required(f):
|
||||||
"""
|
"""
|
||||||
@ -472,22 +464,22 @@ def edit_required(f):
|
|||||||
# Fill indexpage with all requested data from database
|
# Fill indexpage with all requested data from database
|
||||||
def fill_indexpage(page, database, db_filter, order):
|
def fill_indexpage(page, database, db_filter, order):
|
||||||
if current_user.filter_language() != "all":
|
if current_user.filter_language() != "all":
|
||||||
filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
lang_filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
||||||
else:
|
else:
|
||||||
filter = True
|
lang_filter = True
|
||||||
if current_user.show_detail_random():
|
if current_user.show_detail_random():
|
||||||
random = db.session.query(db.Books).filter(filter).order_by(func.random()).limit(config.config_random_books)
|
random = db.session.query(db.Books).filter(lang_filter).order_by(func.random()).limit(config.config_random_books)
|
||||||
else:
|
else:
|
||||||
random = false
|
random = false
|
||||||
off = int(int(config.config_books_per_page) * (page - 1))
|
off = int(int(config.config_books_per_page) * (page - 1))
|
||||||
pagination = Pagination(page, config.config_books_per_page,
|
pagination = Pagination(page, config.config_books_per_page,
|
||||||
len(db.session.query(database).filter(db_filter).filter(filter).all()))
|
len(db.session.query(database).filter(db_filter).filter(lang_filter).all()))
|
||||||
entries = db.session.query(database).filter(db_filter).filter(filter).order_by(order).offset(off).limit(
|
entries = db.session.query(database).filter(db_filter).filter(lang_filter).order_by(order).offset(off).limit(
|
||||||
config.config_books_per_page)
|
config.config_books_per_page)
|
||||||
return entries, random, pagination
|
return entries, random, pagination
|
||||||
|
|
||||||
|
|
||||||
def modify_database_object(input_elements, db_book_object, db_object, db_session, type):
|
def modify_database_object(input_elements, db_book_object, db_object, db_session, db_type):
|
||||||
input_elements = [x for x in input_elements if x != '']
|
input_elements = [x for x in input_elements if x != '']
|
||||||
# we have all input element (authors, series, tags) names now
|
# we have all input element (authors, series, tags) names now
|
||||||
# 1. search for elements to remove
|
# 1. search for elements to remove
|
||||||
@ -519,7 +511,7 @@ def modify_database_object(input_elements, db_book_object, db_object, db_session
|
|||||||
db_session.delete(del_element)
|
db_session.delete(del_element)
|
||||||
# if there are elements to add, we add them now!
|
# if there are elements to add, we add them now!
|
||||||
if len(add_elements) > 0:
|
if len(add_elements) > 0:
|
||||||
if type == 'languages':
|
if db_type == 'languages':
|
||||||
db_filter = db_object.lang_code
|
db_filter = db_object.lang_code
|
||||||
else:
|
else:
|
||||||
db_filter = db_object.name
|
db_filter = db_object.name
|
||||||
@ -528,12 +520,12 @@ def modify_database_object(input_elements, db_book_object, db_object, db_session
|
|||||||
new_element = db_session.query(db_object).filter(db_filter == add_element).first()
|
new_element = db_session.query(db_object).filter(db_filter == add_element).first()
|
||||||
# if no element is found add it
|
# if no element is found add it
|
||||||
if new_element is None:
|
if new_element is None:
|
||||||
if type == 'author':
|
if db_type == 'author':
|
||||||
new_element = db_object(add_element, add_element, "")
|
new_element = db_object(add_element, add_element, "")
|
||||||
else:
|
else:
|
||||||
if type == 'series':
|
if db_type == 'series':
|
||||||
new_element = db_object(add_element, add_element)
|
new_element = db_object(add_element, add_element)
|
||||||
else: # type should be tag, or languages
|
else: # db_type should be tag, or languages
|
||||||
new_element = db_object(add_element)
|
new_element = db_object(add_element)
|
||||||
db_session.add(new_element)
|
db_session.add(new_element)
|
||||||
new_element = db.session.query(db_object).filter(db_filter == add_element).first()
|
new_element = db.session.query(db_object).filter(db_filter == add_element).first()
|
||||||
@ -562,10 +554,6 @@ def before_request():
|
|||||||
@app.route("/opds")
|
@app.route("/opds")
|
||||||
@requires_basic_auth_if_no_ano
|
@requires_basic_auth_if_no_ano
|
||||||
def feed_index():
|
def feed_index():
|
||||||
if current_user.filter_language() != "all":
|
|
||||||
filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
|
||||||
else:
|
|
||||||
filter = True
|
|
||||||
xml = render_title_template('index.xml')
|
xml = render_title_template('index.xml')
|
||||||
response = make_response(xml)
|
response = make_response(xml)
|
||||||
response.headers["Content-Type"] = "application/xml"
|
response.headers["Content-Type"] = "application/xml"
|
||||||
@ -575,7 +563,7 @@ def feed_index():
|
|||||||
@app.route("/opds/osd")
|
@app.route("/opds/osd")
|
||||||
@requires_basic_auth_if_no_ano
|
@requires_basic_auth_if_no_ano
|
||||||
def feed_osd():
|
def feed_osd():
|
||||||
xml = render_title_template('osd.xml',lang='de-DE')
|
xml = render_title_template('osd.xml', lang='de-DE')
|
||||||
response = make_response(xml)
|
response = make_response(xml)
|
||||||
response.headers["Content-Type"] = "application/xml"
|
response.headers["Content-Type"] = "application/xml"
|
||||||
return response
|
return response
|
||||||
@ -595,15 +583,15 @@ def feed_normal_search():
|
|||||||
|
|
||||||
def feed_search(term):
|
def feed_search(term):
|
||||||
if current_user.filter_language() != "all":
|
if current_user.filter_language() != "all":
|
||||||
filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
lang_filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
||||||
else:
|
else:
|
||||||
filter = True
|
lang_filter = True
|
||||||
if term:
|
if term:
|
||||||
entries = db.session.query(db.Books).filter(db.or_(db.Books.tags.any(db.Tags.name.like("%" + term + "%")),
|
entries = db.session.query(db.Books).filter(db.or_(db.Books.tags.any(db.Tags.name.like("%" + term + "%")),
|
||||||
db.Books.series.any(db.Series.name.like("%" + term + "%")),
|
db.Books.series.any(db.Series.name.like("%" + term + "%")),
|
||||||
db.Books.authors.any(db.Authors.name.like("%" + term + "%")),
|
db.Books.authors.any(db.Authors.name.like("%" + term + "%")),
|
||||||
db.Books.publishers.any(db.Publishers.name.like("%" + term + "%")),
|
db.Books.publishers.any(db.Publishers.name.like("%" + term + "%")),
|
||||||
db.Books.title.like("%" + term + "%"))).filter(filter).all()
|
db.Books.title.like("%" + term + "%"))).filter(lang_filter).all()
|
||||||
entriescount = len(entries) if len(entries) > 0 else 1
|
entriescount = len(entries) if len(entries) > 0 else 1
|
||||||
pagination = Pagination(1, entriescount, entriescount)
|
pagination = Pagination(1, entriescount, entriescount)
|
||||||
xml = render_title_template('feed.xml', searchterm=term, entries=entries, pagination=pagination)
|
xml = render_title_template('feed.xml', searchterm=term, entries=entries, pagination=pagination)
|
||||||
@ -620,7 +608,7 @@ def feed_new():
|
|||||||
off = request.args.get("offset")
|
off = request.args.get("offset")
|
||||||
if not off:
|
if not off:
|
||||||
off = 0
|
off = 0
|
||||||
entries, random, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
|
entries, _, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
|
||||||
db.Books, True, db.Books.timestamp.desc())
|
db.Books, True, db.Books.timestamp.desc())
|
||||||
xml = render_title_template('feed.xml', entries=entries, pagination=pagination)
|
xml = render_title_template('feed.xml', entries=entries, pagination=pagination)
|
||||||
response = make_response(xml)
|
response = make_response(xml)
|
||||||
@ -632,10 +620,10 @@ def feed_new():
|
|||||||
@requires_basic_auth_if_no_ano
|
@requires_basic_auth_if_no_ano
|
||||||
def feed_discover():
|
def feed_discover():
|
||||||
if current_user.filter_language() != "all":
|
if current_user.filter_language() != "all":
|
||||||
filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
lang_filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
||||||
else:
|
else:
|
||||||
filter = True
|
lang_filter = True
|
||||||
entries = db.session.query(db.Books).filter(filter).order_by(func.random()).limit(config.config_books_per_page)
|
entries = db.session.query(db.Books).filter(lang_filter).order_by(func.random()).limit(config.config_books_per_page)
|
||||||
pagination = Pagination(1, config.config_books_per_page, int(config.config_books_per_page))
|
pagination = Pagination(1, config.config_books_per_page, int(config.config_books_per_page))
|
||||||
xml = render_title_template('feed.xml', entries=entries, pagination=pagination)
|
xml = render_title_template('feed.xml', entries=entries, pagination=pagination)
|
||||||
response = make_response(xml)
|
response = make_response(xml)
|
||||||
@ -663,9 +651,9 @@ def feed_hot():
|
|||||||
if not off:
|
if not off:
|
||||||
off = 0
|
off = 0
|
||||||
if current_user.filter_language() != "all":
|
if current_user.filter_language() != "all":
|
||||||
filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
lang_filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
||||||
else:
|
else:
|
||||||
filter = True
|
lang_filter = True
|
||||||
all_books = ub.session.query(ub.Downloads, ub.func.count(ub.Downloads.book_id)).order_by(
|
all_books = ub.session.query(ub.Downloads, ub.func.count(ub.Downloads.book_id)).order_by(
|
||||||
ub.func.count(ub.Downloads.book_id).desc()).group_by(ub.Downloads.book_id)
|
ub.func.count(ub.Downloads.book_id).desc()).group_by(ub.Downloads.book_id)
|
||||||
hot_books = all_books.offset(off).limit(config.config_books_per_page)
|
hot_books = all_books.offset(off).limit(config.config_books_per_page)
|
||||||
@ -674,7 +662,7 @@ def feed_hot():
|
|||||||
downloadBook = db.session.query(db.Books).filter(db.Books.id == book.Downloads.book_id).first()
|
downloadBook = db.session.query(db.Books).filter(db.Books.id == book.Downloads.book_id).first()
|
||||||
if downloadBook:
|
if downloadBook:
|
||||||
entries.append(
|
entries.append(
|
||||||
db.session.query(db.Books).filter(filter).filter(db.Books.id == book.Downloads.book_id).first())
|
db.session.query(db.Books).filter(lang_filter).filter(db.Books.id == book.Downloads.book_id).first())
|
||||||
else:
|
else:
|
||||||
ub.session.query(ub.Downloads).filter(book.Downloads.book_id == ub.Downloads.book_id).delete()
|
ub.session.query(ub.Downloads).filter(book.Downloads.book_id == ub.Downloads.book_id).delete()
|
||||||
ub.session.commit()
|
ub.session.commit()
|
||||||
@ -693,10 +681,10 @@ def feed_authorindex():
|
|||||||
if not off:
|
if not off:
|
||||||
off = 0
|
off = 0
|
||||||
if current_user.filter_language() != "all":
|
if current_user.filter_language() != "all":
|
||||||
filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
lang_filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
||||||
else:
|
else:
|
||||||
filter = True
|
lang_filter = True
|
||||||
entries = db.session.query(db.Authors).join(db.books_authors_link).join(db.Books).filter(filter)\
|
entries = db.session.query(db.Authors).join(db.books_authors_link).join(db.Books).filter(lang_filter)\
|
||||||
.group_by('books_authors_link.author').order_by(db.Authors.sort).limit(config.config_books_per_page).offset(off)
|
.group_by('books_authors_link.author').order_by(db.Authors.sort).limit(config.config_books_per_page).offset(off)
|
||||||
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
|
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
|
||||||
len(db.session.query(db.Authors).all()))
|
len(db.session.query(db.Authors).all()))
|
||||||
@ -706,14 +694,14 @@ def feed_authorindex():
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
@app.route("/opds/author/<int:id>")
|
@app.route("/opds/author/<int:book_id>")
|
||||||
@requires_basic_auth_if_no_ano
|
@requires_basic_auth_if_no_ano
|
||||||
def feed_author(id):
|
def feed_author(book_id):
|
||||||
off = request.args.get("offset")
|
off = request.args.get("offset")
|
||||||
if not off:
|
if not off:
|
||||||
off = 0
|
off = 0
|
||||||
entries, random, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
|
entries, random, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
|
||||||
db.Books, db.Books.authors.any(db.Authors.id == id), db.Books.timestamp.desc())
|
db.Books, db.Books.authors.any(db.Authors.id == book_id), db.Books.timestamp.desc())
|
||||||
xml = render_title_template('feed.xml', entries=entries, pagination=pagination)
|
xml = render_title_template('feed.xml', entries=entries, pagination=pagination)
|
||||||
response = make_response(xml)
|
response = make_response(xml)
|
||||||
response.headers["Content-Type"] = "application/xml"
|
response.headers["Content-Type"] = "application/xml"
|
||||||
@ -727,10 +715,10 @@ def feed_categoryindex():
|
|||||||
if not off:
|
if not off:
|
||||||
off = 0
|
off = 0
|
||||||
if current_user.filter_language() != "all":
|
if current_user.filter_language() != "all":
|
||||||
filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
lang_filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
||||||
else:
|
else:
|
||||||
filter = True
|
lang_filter = True
|
||||||
entries = db.session.query(db.Tags).join(db.books_tags_link).join(db.Books).filter(filter).\
|
entries = db.session.query(db.Tags).join(db.books_tags_link).join(db.Books).filter(lang_filter).\
|
||||||
group_by('books_tags_link.tag').order_by(db.Tags.name).offset(off).limit(config.config_books_per_page)
|
group_by('books_tags_link.tag').order_by(db.Tags.name).offset(off).limit(config.config_books_per_page)
|
||||||
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
|
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
|
||||||
len(db.session.query(db.Tags).all()))
|
len(db.session.query(db.Tags).all()))
|
||||||
@ -740,14 +728,14 @@ def feed_categoryindex():
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
@app.route("/opds/category/<int:id>")
|
@app.route("/opds/category/<int:book_id>")
|
||||||
@requires_basic_auth_if_no_ano
|
@requires_basic_auth_if_no_ano
|
||||||
def feed_category(id):
|
def feed_category(book_id):
|
||||||
off = request.args.get("offset")
|
off = request.args.get("offset")
|
||||||
if not off:
|
if not off:
|
||||||
off = 0
|
off = 0
|
||||||
entries, random, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
|
entries, random, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
|
||||||
db.Books, db.Books.tags.any(db.Tags.id == id), db.Books.timestamp.desc())
|
db.Books, db.Books.tags.any(db.Tags.id == book_id), db.Books.timestamp.desc())
|
||||||
xml = render_title_template('feed.xml', entries=entries, pagination=pagination)
|
xml = render_title_template('feed.xml', entries=entries, pagination=pagination)
|
||||||
response = make_response(xml)
|
response = make_response(xml)
|
||||||
response.headers["Content-Type"] = "application/xml"
|
response.headers["Content-Type"] = "application/xml"
|
||||||
@ -761,10 +749,10 @@ def feed_seriesindex():
|
|||||||
if not off:
|
if not off:
|
||||||
off = 0
|
off = 0
|
||||||
if current_user.filter_language() != "all":
|
if current_user.filter_language() != "all":
|
||||||
filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
lang_filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
||||||
else:
|
else:
|
||||||
filter = True
|
lang_filter = True
|
||||||
entries = db.session.query(db.Series).join(db.books_series_link).join(db.Books).filter(filter).\
|
entries = db.session.query(db.Series).join(db.books_series_link).join(db.Books).filter(lang_filter).\
|
||||||
group_by('books_series_link.series').order_by(db.Series.sort).offset(off).all()
|
group_by('books_series_link.series').order_by(db.Series.sort).offset(off).all()
|
||||||
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
|
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
|
||||||
len(db.session.query(db.Series).all()))
|
len(db.session.query(db.Series).all()))
|
||||||
@ -774,14 +762,14 @@ def feed_seriesindex():
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
@app.route("/opds/series/<int:id>")
|
@app.route("/opds/series/<int:book_id>")
|
||||||
@requires_basic_auth_if_no_ano
|
@requires_basic_auth_if_no_ano
|
||||||
def feed_series(id):
|
def feed_series(book_id):
|
||||||
off = request.args.get("offset")
|
off = request.args.get("offset")
|
||||||
if not off:
|
if not off:
|
||||||
off = 0
|
off = 0
|
||||||
entries, random, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
|
entries, random, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
|
||||||
db.Books, db.Books.series.any(db.Series.id == id),db.Books.series_index)
|
db.Books, db.Books.series.any(db.Series.id == book_id),db.Books.series_index)
|
||||||
xml = render_title_template('feed.xml', entries=entries, pagination=pagination)
|
xml = render_title_template('feed.xml', entries=entries, pagination=pagination)
|
||||||
response = make_response(xml)
|
response = make_response(xml)
|
||||||
response.headers["Content-Type"] = "application/xml"
|
response.headers["Content-Type"] = "application/xml"
|
||||||
@ -796,13 +784,12 @@ def partial(total_byte_len, part_size_limit):
|
|||||||
return s
|
return s
|
||||||
|
|
||||||
def do_gdrive_download(df, headers):
|
def do_gdrive_download(df, headers):
|
||||||
startTime=time.time()
|
|
||||||
total_size = int(df.metadata.get('fileSize'))
|
total_size = int(df.metadata.get('fileSize'))
|
||||||
download_url = df.metadata.get('downloadUrl')
|
download_url = df.metadata.get('downloadUrl')
|
||||||
s = partial(total_size, 1024 * 1024) # I'm downloading BIG files, so 100M chunk size is fine for me
|
s = partial(total_size, 1024 * 1024) # I'm downloading BIG files, so 100M chunk size is fine for me
|
||||||
def stream():
|
def stream():
|
||||||
for bytes in s:
|
for byte in s:
|
||||||
headers = {"Range" : 'bytes=%s-%s' % (bytes[0], bytes[1])}
|
headers = {"Range" : 'bytes=%s-%s' % (byte[0], byte[1])}
|
||||||
resp, content = df.auth.Get_Http_Object().request(download_url, headers=headers)
|
resp, content = df.auth.Get_Http_Object().request(download_url, headers=headers)
|
||||||
if resp.status == 206 :
|
if resp.status == 206 :
|
||||||
yield content
|
yield content
|
||||||
@ -811,14 +798,14 @@ def do_gdrive_download(df, headers):
|
|||||||
return
|
return
|
||||||
return Response(stream_with_context(stream()), headers=headers)
|
return Response(stream_with_context(stream()), headers=headers)
|
||||||
|
|
||||||
@app.route("/opds/download/<book_id>/<format>/")
|
@app.route("/opds/download/<book_id>/<book_format>/")
|
||||||
@requires_basic_auth_if_no_ano
|
@requires_basic_auth_if_no_ano
|
||||||
@download_required
|
@download_required
|
||||||
def get_opds_download_link(book_id, format):
|
def get_opds_download_link(book_id, book_format):
|
||||||
startTime=time.time()
|
startTime=time.time()
|
||||||
format = format.split(".")[0]
|
book_format = book_format.split(".")[0]
|
||||||
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()
|
||||||
data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == format.upper()).first()
|
data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == book_format.upper()).first()
|
||||||
app.logger.info (data.name)
|
app.logger.info (data.name)
|
||||||
if current_user.is_authenticated:
|
if current_user.is_authenticated:
|
||||||
helper.update_download(book_id, int(current_user.id))
|
helper.update_download(book_id, int(current_user.id))
|
||||||
@ -826,18 +813,18 @@ def get_opds_download_link(book_id, format):
|
|||||||
if len(book.authors) > 0:
|
if len(book.authors) > 0:
|
||||||
file_name = book.authors[0].name + '_' + file_name
|
file_name = book.authors[0].name + '_' + file_name
|
||||||
file_name = helper.get_valid_filename(file_name)
|
file_name = helper.get_valid_filename(file_name)
|
||||||
headers={}
|
headers = Headers ()
|
||||||
headers["Content-Disposition"] = "attachment; filename*=UTF-8''%s.%s" % (quote(file_name.encode('utf8')), format)
|
headers["Content-Disposition"] = "attachment; filename*=UTF-8''%s.%s" % (quote(file_name.encode('utf8')), book_format)
|
||||||
app.logger.info (time.time()-startTime)
|
app.logger.info (time.time()-startTime)
|
||||||
startTime=time.time()
|
startTime=time.time()
|
||||||
if config.config_use_google_drive:
|
if config.config_use_google_drive:
|
||||||
df=gdriveutils.getFileFromEbooksFolder(Gdrive.Instance().drive, book.path, data.name + "." + format)
|
app.logger.info(time.time() - startTime)
|
||||||
|
df=gdriveutils.getFileFromEbooksFolder(Gdrive.Instance().drive, book.path, data.name + "." + book_format)
|
||||||
return do_gdrive_download(df, headers)
|
return do_gdrive_download(df, headers)
|
||||||
else:
|
else:
|
||||||
# file_name = helper.get_valid_filename(file_name)
|
response = make_response(send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + book_format))
|
||||||
response = make_response(send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + format))
|
response.headers=headers
|
||||||
response.headers=headers
|
return response
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/ajax/book/<string:uuid>")
|
@app.route("/ajax/book/<string:uuid>")
|
||||||
@ -858,8 +845,9 @@ def get_metadata_calibre_companion(uuid):
|
|||||||
def get_authors_json():
|
def get_authors_json():
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
query = request.args.get('q')
|
query = request.args.get('q')
|
||||||
entries = db.session.execute("select name from authors where name like '%" + query + "%'")
|
# entries = db.session.execute("select name from authors where name like '%" + query + "%'")
|
||||||
json_dumps = json.dumps([dict(r) for r in entries])
|
entries = db.session.query(db.Authors).filter(db.Authors.name.like("%" + query + "%")).all()
|
||||||
|
json_dumps = json.dumps([dict(name=r.name) for r in entries])
|
||||||
return json_dumps
|
return json_dumps
|
||||||
|
|
||||||
|
|
||||||
@ -868,8 +856,11 @@ def get_authors_json():
|
|||||||
def get_tags_json():
|
def get_tags_json():
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
query = request.args.get('q')
|
query = request.args.get('q')
|
||||||
entries = db.session.execute("select name from tags where name like '%" + query + "%'")
|
# entries = db.session.execute("select name from tags where name like '%" + query + "%'")
|
||||||
json_dumps = json.dumps([dict(r) for r in entries])
|
entries = db.session.query(db.Tags).filter(db.Tags.name.like("%" + query + "%")).all()
|
||||||
|
#for x in entries:
|
||||||
|
# alfa = dict(name=x.name)
|
||||||
|
json_dumps = json.dumps([dict(name=r.name) for r in entries])
|
||||||
return json_dumps
|
return json_dumps
|
||||||
|
|
||||||
@app.route("/get_update_status", methods=['GET'])
|
@app.route("/get_update_status", methods=['GET'])
|
||||||
@ -915,7 +906,7 @@ def get_updater_status():
|
|||||||
elif request.method == "GET":
|
elif request.method == "GET":
|
||||||
try:
|
try:
|
||||||
status['status']=helper.updater_thread.get_update_status()
|
status['status']=helper.updater_thread.get_update_status()
|
||||||
except Exception as e:
|
except Exception:
|
||||||
status['status'] = 7
|
status['status'] = 7
|
||||||
return json.dumps(status)
|
return json.dumps(status)
|
||||||
|
|
||||||
@ -930,7 +921,7 @@ def get_languages_json():
|
|||||||
try:
|
try:
|
||||||
cur_l = LC.parse(lang.lang_code)
|
cur_l = LC.parse(lang.lang_code)
|
||||||
lang.name = cur_l.get_language_name(get_locale())
|
lang.name = cur_l.get_language_name(get_locale())
|
||||||
except Exception as e:
|
except Exception:
|
||||||
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
||||||
entries = [s for s in languages if query in s.name.lower()]
|
entries = [s for s in languages if query in s.name.lower()]
|
||||||
json_dumps = json.dumps([dict(name=r.name) for r in entries])
|
json_dumps = json.dumps([dict(name=r.name) for r in entries])
|
||||||
@ -942,8 +933,9 @@ def get_languages_json():
|
|||||||
def get_series_json():
|
def get_series_json():
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
query = request.args.get('q')
|
query = request.args.get('q')
|
||||||
entries = db.session.execute("select name from series where name like '%" + query + "%'")
|
entries = db.session.query(db.Series).filter(db.Series.name.like("%" + query + "%")).all()
|
||||||
json_dumps = json.dumps([dict(r) for r in entries])
|
# entries = db.session.execute("select name from series where name like '%" + query + "%'")
|
||||||
|
json_dumps = json.dumps([dict(name=r.name) for r in entries])
|
||||||
return json_dumps
|
return json_dumps
|
||||||
|
|
||||||
|
|
||||||
@ -987,11 +979,11 @@ def index(page):
|
|||||||
@login_required_if_no_ano
|
@login_required_if_no_ano
|
||||||
def hot_books(page):
|
def hot_books(page):
|
||||||
if current_user.filter_language() != "all":
|
if current_user.filter_language() != "all":
|
||||||
filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
lang_filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
||||||
else:
|
else:
|
||||||
filter = True
|
lang_filter = True
|
||||||
if current_user.show_detail_random():
|
if current_user.show_detail_random():
|
||||||
random = db.session.query(db.Books).filter(filter).order_by(func.random()).limit(config.config_random_books)
|
random = db.session.query(db.Books).filter(lang_filter).order_by(func.random()).limit(config.config_random_books)
|
||||||
else:
|
else:
|
||||||
random = false
|
random = false
|
||||||
off = int(int(config.config_books_per_page) * (page - 1))
|
off = int(int(config.config_books_per_page) * (page - 1))
|
||||||
@ -1003,7 +995,7 @@ def hot_books(page):
|
|||||||
downloadBook = db.session.query(db.Books).filter(db.Books.id == book.Downloads.book_id).first()
|
downloadBook = db.session.query(db.Books).filter(db.Books.id == book.Downloads.book_id).first()
|
||||||
if downloadBook:
|
if downloadBook:
|
||||||
entries.append(
|
entries.append(
|
||||||
db.session.query(db.Books).filter(filter).filter(db.Books.id == book.Downloads.book_id).first())
|
db.session.query(db.Books).filter(lang_filter).filter(db.Books.id == book.Downloads.book_id).first())
|
||||||
else:
|
else:
|
||||||
ub.session.query(ub.Downloads).filter(book.Downloads.book_id == ub.Downloads.book_id).delete()
|
ub.session.query(ub.Downloads).filter(book.Downloads.book_id == ub.Downloads.book_id).delete()
|
||||||
ub.session.commit()
|
ub.session.commit()
|
||||||
@ -1036,22 +1028,22 @@ def discover(page):
|
|||||||
@login_required_if_no_ano
|
@login_required_if_no_ano
|
||||||
def author_list():
|
def author_list():
|
||||||
if current_user.filter_language() != "all":
|
if current_user.filter_language() != "all":
|
||||||
filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
lang_filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
||||||
else:
|
else:
|
||||||
filter = True
|
lang_filter = True
|
||||||
entries = db.session.query(db.Authors, func.count('books_authors_link.book').label('count')).join(
|
entries = db.session.query(db.Authors, func.count('books_authors_link.book').label('count')).join(
|
||||||
db.books_authors_link).join(db.Books).filter(
|
db.books_authors_link).join(db.Books).filter(
|
||||||
filter).group_by('books_authors_link.author').order_by(db.Authors.sort).all()
|
lang_filter).group_by('books_authors_link.author').order_by(db.Authors.sort).all()
|
||||||
return render_title_template('list.html', entries=entries, folder='author', title=_(u"Author list"))
|
return render_title_template('list.html', entries=entries, folder='author', title=_(u"Author list"))
|
||||||
|
|
||||||
|
|
||||||
@app.route("/author/<int:id>", defaults={'page': 1})
|
@app.route("/author/<int:book_id>", defaults={'page': 1})
|
||||||
@app.route("/author/<int:id>/<int:page>'")
|
@app.route("/author/<int:book_id>/<int:page>'")
|
||||||
@login_required_if_no_ano
|
@login_required_if_no_ano
|
||||||
def author(id,page):
|
def author(book_id,page):
|
||||||
entries, random, pagination = fill_indexpage(page, db.Books, db.Books.authors.any(db.Authors.id == id),
|
entries, random, pagination = fill_indexpage(page, db.Books, db.Books.authors.any(db.Authors.id == book_id),
|
||||||
db.Books.timestamp.desc())
|
db.Books.timestamp.desc())
|
||||||
name = db.session.query(db.Authors).filter(db.Authors.id == id).first().name
|
name = db.session.query(db.Authors).filter(db.Authors.id == book_id).first().name
|
||||||
if entries:
|
if entries:
|
||||||
return render_title_template('index.html', random=random, entries=entries, title=_(u"Author: %(name)s", name=name))
|
return render_title_template('index.html', random=random, entries=entries, title=_(u"Author: %(name)s", name=name))
|
||||||
else:
|
else:
|
||||||
@ -1063,22 +1055,22 @@ def author(id,page):
|
|||||||
@login_required_if_no_ano
|
@login_required_if_no_ano
|
||||||
def series_list():
|
def series_list():
|
||||||
if current_user.filter_language() != "all":
|
if current_user.filter_language() != "all":
|
||||||
filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
lang_filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
||||||
else:
|
else:
|
||||||
filter = True
|
lang_filter = True
|
||||||
entries = db.session.query(db.Series, func.count('books_series_link.book').label('count')).join(
|
entries = db.session.query(db.Series, func.count('books_series_link.book').label('count')).join(
|
||||||
db.books_series_link).join(db.Books).filter(
|
db.books_series_link).join(db.Books).filter(
|
||||||
filter).group_by('books_series_link.series').order_by(db.Series.sort).all()
|
lang_filter).group_by('books_series_link.series').order_by(db.Series.sort).all()
|
||||||
return render_title_template('list.html', entries=entries, folder='series', title=_(u"Series list"))
|
return render_title_template('list.html', entries=entries, folder='series', title=_(u"Series list"))
|
||||||
|
|
||||||
|
|
||||||
@app.route("/series/<int:id>/", defaults={'page': 1})
|
@app.route("/series/<int:book_id>/", defaults={'page': 1})
|
||||||
@app.route("/series/<int:id>/<int:page>'")
|
@app.route("/series/<int:book_id>/<int:page>'")
|
||||||
@login_required_if_no_ano
|
@login_required_if_no_ano
|
||||||
def series(id, page):
|
def series(book_id, page):
|
||||||
entries, random, pagination = fill_indexpage(page, db.Books, db.Books.series.any(db.Series.id == id),
|
entries, random, pagination = fill_indexpage(page, db.Books, db.Books.series.any(db.Series.id == book_id),
|
||||||
db.Books.series_index)
|
db.Books.series_index)
|
||||||
name=db.session.query(db.Series).filter(db.Series.id == id).first().name
|
name=db.session.query(db.Series).filter(db.Series.id == book_id).first().name
|
||||||
if entries:
|
if entries:
|
||||||
return render_title_template('index.html', random=random, pagination=pagination, entries=entries,
|
return render_title_template('index.html', random=random, pagination=pagination, entries=entries,
|
||||||
title=_(u"Series: %(serie)s", serie=name))
|
title=_(u"Series: %(serie)s", serie=name))
|
||||||
@ -1096,13 +1088,13 @@ def language_overview():
|
|||||||
try:
|
try:
|
||||||
cur_l = LC.parse(lang.lang_code)
|
cur_l = LC.parse(lang.lang_code)
|
||||||
lang.name = cur_l.get_language_name(get_locale())
|
lang.name = cur_l.get_language_name(get_locale())
|
||||||
except Exception as e:
|
except Exception:
|
||||||
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
langfound = 1
|
langfound = 1
|
||||||
cur_l = LC.parse(current_user.filter_language())
|
cur_l = LC.parse(current_user.filter_language())
|
||||||
except Exception as e:
|
except Exception:
|
||||||
langfound = 0
|
langfound = 0
|
||||||
languages = db.session.query(db.Languages).filter(
|
languages = db.session.query(db.Languages).filter(
|
||||||
db.Languages.lang_code == current_user.filter_language()).all()
|
db.Languages.lang_code == current_user.filter_language()).all()
|
||||||
@ -1126,7 +1118,7 @@ def language(name, page):
|
|||||||
try:
|
try:
|
||||||
cur_l = LC.parse(name)
|
cur_l = LC.parse(name)
|
||||||
name = cur_l.get_language_name(get_locale())
|
name = cur_l.get_language_name(get_locale())
|
||||||
except Exception as e:
|
except Exception:
|
||||||
name = _(isoLanguages.get(part3=name).name)
|
name = _(isoLanguages.get(part3=name).name)
|
||||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
||||||
title=_(u"Language: %(name)s", name=name))
|
title=_(u"Language: %(name)s", name=name))
|
||||||
@ -1136,58 +1128,58 @@ def language(name, page):
|
|||||||
@login_required_if_no_ano
|
@login_required_if_no_ano
|
||||||
def category_list():
|
def category_list():
|
||||||
if current_user.filter_language() != "all":
|
if current_user.filter_language() != "all":
|
||||||
filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
lang_filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
||||||
else:
|
else:
|
||||||
filter = True
|
lang_filter = True
|
||||||
entries = db.session.query(db.Tags, func.count('books_tags_link.book').label('count')).join(
|
entries = db.session.query(db.Tags, func.count('books_tags_link.book').label('count')).join(
|
||||||
db.books_tags_link).join(db.Books).filter(
|
db.books_tags_link).join(db.Books).filter(
|
||||||
filter).group_by('books_tags_link.tag').all()
|
lang_filter).group_by('books_tags_link.tag').all()
|
||||||
return render_title_template('list.html', entries=entries, folder='category', title=_(u"Category list"))
|
return render_title_template('list.html', entries=entries, folder='category', title=_(u"Category list"))
|
||||||
|
|
||||||
|
|
||||||
@app.route("/category/<int:id>", defaults={'page': 1})
|
@app.route("/category/<int:book_id>", defaults={'page': 1})
|
||||||
@app.route('/category/<int:id>/<int:page>')
|
@app.route('/category/<int:book_id>/<int:page>')
|
||||||
@login_required_if_no_ano
|
@login_required_if_no_ano
|
||||||
def category(id, page):
|
def category(book_id, page):
|
||||||
entries, random, pagination = fill_indexpage(page, db.Books, db.Books.tags.any(db.Tags.id == id),
|
entries, random, pagination = fill_indexpage(page, db.Books, db.Books.tags.any(db.Tags.id == book_id),
|
||||||
db.Books.timestamp.desc())
|
db.Books.timestamp.desc())
|
||||||
|
|
||||||
name=db.session.query(db.Tags).filter(db.Tags.id == id).first().name
|
name=db.session.query(db.Tags).filter(db.Tags.id == book_id).first().name
|
||||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
||||||
title=_(u"Category: %(name)s", name=name))
|
title=_(u"Category: %(name)s", name=name))
|
||||||
|
|
||||||
|
|
||||||
@app.route("/ajax/toggleread/<int:id>", methods=['POST'])
|
@app.route("/ajax/toggleread/<int:book_id>", methods=['POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def toggle_read(id):
|
def toggle_read(book_id):
|
||||||
book = ub.session.query(ub.ReadBook).filter(ub.and_(ub.ReadBook.user_id == int(current_user.id),
|
book = ub.session.query(ub.ReadBook).filter(ub.and_(ub.ReadBook.user_id == int(current_user.id),
|
||||||
ub.ReadBook.book_id == id)).first()
|
ub.ReadBook.book_id == book_id)).first()
|
||||||
if book:
|
if book:
|
||||||
book.is_read=not book.is_read
|
book.is_read=not book.is_read
|
||||||
else:
|
else:
|
||||||
readBook=ub.ReadBook()
|
readBook=ub.ReadBook()
|
||||||
readBook.user_id=int(current_user.id)
|
readBook.user_id=int(current_user.id)
|
||||||
readBook.book_id = id
|
readBook.book_id = book_id
|
||||||
readBook.is_read=True
|
readBook.is_read=True
|
||||||
book=readBook
|
book=readBook
|
||||||
ub.session.merge(book)
|
ub.session.merge(book)
|
||||||
ub.session.commit()
|
ub.session.commit()
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@app.route("/book/<int:id>")
|
@app.route("/book/<int:book_id>")
|
||||||
@login_required_if_no_ano
|
@login_required_if_no_ano
|
||||||
def show_book(id):
|
def show_book(book_id):
|
||||||
if current_user.filter_language() != "all":
|
if current_user.filter_language() != "all":
|
||||||
filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
lang_filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
||||||
else:
|
else:
|
||||||
filter = True
|
lang_filter = True
|
||||||
entries = db.session.query(db.Books).filter(db.Books.id == id).filter(filter).first()
|
entries = db.session.query(db.Books).filter(db.Books.id == book_id).filter(lang_filter).first()
|
||||||
if entries:
|
if entries:
|
||||||
for index in range(0, len(entries.languages)):
|
for index in range(0, len(entries.languages)):
|
||||||
try:
|
try:
|
||||||
entries.languages[index].language_name = LC.parse(entries.languages[index].lang_code).get_language_name(
|
entries.languages[index].language_name = LC.parse(entries.languages[index].lang_code).get_language_name(
|
||||||
get_locale())
|
get_locale())
|
||||||
except Exception as e:
|
except Exception:
|
||||||
entries.languages[index].language_name = _(
|
entries.languages[index].language_name = _(
|
||||||
isoLanguages.get(part3=entries.languages[index].lang_code).name)
|
isoLanguages.get(part3=entries.languages[index].lang_code).name)
|
||||||
tmpcc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
|
tmpcc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
|
||||||
@ -1201,7 +1193,7 @@ def show_book(id):
|
|||||||
else:
|
else:
|
||||||
cc=tmpcc
|
cc=tmpcc
|
||||||
book_in_shelfs = []
|
book_in_shelfs = []
|
||||||
shelfs = ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == id).all()
|
shelfs = ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book_id).all()
|
||||||
for entry in shelfs:
|
for entry in shelfs:
|
||||||
book_in_shelfs.append(entry.shelf)
|
book_in_shelfs.append(entry.shelf)
|
||||||
|
|
||||||
@ -1209,7 +1201,7 @@ def show_book(id):
|
|||||||
# title=entries.title, books_shelfs=book_in_shelfs)
|
# title=entries.title, books_shelfs=book_in_shelfs)
|
||||||
if not current_user.is_anonymous():
|
if not current_user.is_anonymous():
|
||||||
matching_have_read_book=ub.session.query(ub.ReadBook).filter(ub.and_(ub.ReadBook.user_id == int(current_user.id),
|
matching_have_read_book=ub.session.query(ub.ReadBook).filter(ub.and_(ub.ReadBook.user_id == int(current_user.id),
|
||||||
ub.ReadBook.book_id == id)).all()
|
ub.ReadBook.book_id == book_id)).all()
|
||||||
have_read=len(matching_have_read_book) > 0 and matching_have_read_book[0].is_read
|
have_read=len(matching_have_read_book) > 0 and matching_have_read_book[0].is_read
|
||||||
else:
|
else:
|
||||||
have_read=None
|
have_read=None
|
||||||
@ -1242,11 +1234,10 @@ def stats():
|
|||||||
kindlegen = os.path.join(vendorpath, u"kindlegen")
|
kindlegen = os.path.join(vendorpath, u"kindlegen")
|
||||||
versions['KindlegenVersion'] = _('not installed')
|
versions['KindlegenVersion'] = _('not installed')
|
||||||
if os.path.exists(kindlegen):
|
if os.path.exists(kindlegen):
|
||||||
p = subprocess.Popen(kindlegen, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
p = subprocess.Popen(kindlegen, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
stdin=subprocess.PIPE)
|
|
||||||
p.wait()
|
p.wait()
|
||||||
for lines in p.stdout.readlines():
|
for lines in p.stdout.readlines():
|
||||||
if type(lines) is bytes:
|
if isinstance(lines, bytes):
|
||||||
lines = lines.decode('utf-8')
|
lines = lines.decode('utf-8')
|
||||||
if re.search('Amazon kindlegen\(', lines):
|
if re.search('Amazon kindlegen\(', lines):
|
||||||
versions['KindlegenVersion'] = lines
|
versions['KindlegenVersion'] = lines
|
||||||
@ -1308,7 +1299,7 @@ def revoke_watch_gdrive():
|
|||||||
last_watch_response=config.config_google_drive_watch_changes_response
|
last_watch_response=config.config_google_drive_watch_changes_response
|
||||||
if last_watch_response:
|
if last_watch_response:
|
||||||
try:
|
try:
|
||||||
response=gdriveutils.stopChannel(Gdrive.Instance().drive, last_watch_response['id'], last_watch_response['resourceId'])
|
gdriveutils.stopChannel(Gdrive.Instance().drive, last_watch_response['id'], last_watch_response['resourceId'])
|
||||||
except HttpError:
|
except HttpError:
|
||||||
pass
|
pass
|
||||||
settings = ub.session.query(ub.Settings).first()
|
settings = ub.session.query(ub.Settings).first()
|
||||||
@ -1340,13 +1331,13 @@ def on_received_watch_confirmation():
|
|||||||
if not response['deleted'] and response['file']['title'] == 'metadata.db' and response['file']['md5Checksum'] != md5(dbpath):
|
if not response['deleted'] and response['file']['title'] == 'metadata.db' and response['file']['md5Checksum'] != md5(dbpath):
|
||||||
tmpDir=tempfile.gettempdir()
|
tmpDir=tempfile.gettempdir()
|
||||||
app.logger.info ('Database file updated')
|
app.logger.info ('Database file updated')
|
||||||
copyfile (dbpath, tmpDir + "/metadata.db_" + str(current_milli_time()))
|
copyfile (dbpath, os.path.join(tmpDir, "metadata.db_" + str(current_milli_time())))
|
||||||
app.logger.info ('Backing up existing and downloading updated metadata.db')
|
app.logger.info ('Backing up existing and downloading updated metadata.db')
|
||||||
gdriveutils.downloadFile(Gdrive.Instance().drive, None, "metadata.db", tmpDir + "/tmp_metadata.db")
|
gdriveutils.downloadFile(Gdrive.Instance().drive, None, "metadata.db", os.path.join(tmpDir, "tmp_metadata.db"))
|
||||||
app.logger.info ('Setting up new DB')
|
app.logger.info ('Setting up new DB')
|
||||||
os.rename(tmpDir + "/tmp_metadata.db", dbpath)
|
os.rename(os.path.join(tmpDir, "tmp_metadata.db"), dbpath)
|
||||||
db.setup_db()
|
db.setup_db()
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
app.logger.exception(e)
|
app.logger.exception(e)
|
||||||
|
|
||||||
updateMetaData()
|
updateMetaData()
|
||||||
@ -1389,7 +1380,7 @@ def shutdown():
|
|||||||
def update():
|
def update():
|
||||||
helper.updater_thread = helper.Updater()
|
helper.updater_thread = helper.Updater()
|
||||||
flash(_(u"Update done"), category="info")
|
flash(_(u"Update done"), category="info")
|
||||||
return ""
|
return abort(404)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/search", methods=["GET"])
|
@app.route("/search", methods=["GET"])
|
||||||
@ -1398,14 +1389,14 @@ def search():
|
|||||||
term = request.args.get("query").strip()
|
term = request.args.get("query").strip()
|
||||||
if term:
|
if term:
|
||||||
if current_user.filter_language() != "all":
|
if current_user.filter_language() != "all":
|
||||||
filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
lang_filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
||||||
else:
|
else:
|
||||||
filter = True
|
lang_filter = True
|
||||||
entries = db.session.query(db.Books).filter(db.or_(db.Books.tags.any(db.Tags.name.like("%" + term + "%")),
|
entries = db.session.query(db.Books).filter(db.or_(db.Books.tags.any(db.Tags.name.like("%" + term + "%")),
|
||||||
db.Books.series.any(db.Series.name.like("%" + term + "%")),
|
db.Books.series.any(db.Series.name.like("%" + term + "%")),
|
||||||
db.Books.authors.any(db.Authors.name.like("%" + term + "%")),
|
db.Books.authors.any(db.Authors.name.like("%" + term + "%")),
|
||||||
db.Books.publishers.any(db.Publishers.name.like("%" + term + "%")),
|
db.Books.publishers.any(db.Publishers.name.like("%" + term + "%")),
|
||||||
db.Books.title.like("%" + term + "%"))).filter(filter).all()
|
db.Books.title.like("%" + term + "%"))).filter(lang_filter).all()
|
||||||
return render_title_template('search.html', searchterm=term, entries=entries)
|
return render_title_template('search.html', searchterm=term, entries=entries)
|
||||||
else:
|
else:
|
||||||
return render_title_template('search.html', searchterm="")
|
return render_title_template('search.html', searchterm="")
|
||||||
@ -1443,7 +1434,7 @@ def advanced_search():
|
|||||||
try:
|
try:
|
||||||
cur_l = LC.parse(lang.lang_code)
|
cur_l = LC.parse(lang.lang_code)
|
||||||
lang.name = cur_l.get_language_name(get_locale())
|
lang.name = cur_l.get_language_name(get_locale())
|
||||||
except Exception as e:
|
except Exception:
|
||||||
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
||||||
searchterm.extend(language.name for language in language_names)
|
searchterm.extend(language.name for language in language_names)
|
||||||
searchterm = " + ".join(filter(None, searchterm))
|
searchterm = " + ".join(filter(None, searchterm))
|
||||||
@ -1475,7 +1466,7 @@ def advanced_search():
|
|||||||
try:
|
try:
|
||||||
cur_l = LC.parse(lang.lang_code)
|
cur_l = LC.parse(lang.lang_code)
|
||||||
lang.name = cur_l.get_language_name(get_locale())
|
lang.name = cur_l.get_language_name(get_locale())
|
||||||
except Exception as e:
|
except Exception:
|
||||||
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
||||||
else:
|
else:
|
||||||
languages = None
|
languages = None
|
||||||
@ -1485,7 +1476,7 @@ def advanced_search():
|
|||||||
def get_cover_via_gdrive(cover_path):
|
def get_cover_via_gdrive(cover_path):
|
||||||
df=gdriveutils.getFileFromEbooksFolder(Gdrive.Instance().drive, cover_path, 'cover.jpg')
|
df=gdriveutils.getFileFromEbooksFolder(Gdrive.Instance().drive, cover_path, 'cover.jpg')
|
||||||
if not gdriveutils.session.query(gdriveutils.PermissionAdded).filter(gdriveutils.PermissionAdded.gdrive_id == df['id']).first():
|
if not gdriveutils.session.query(gdriveutils.PermissionAdded).filter(gdriveutils.PermissionAdded.gdrive_id == df['id']).first():
|
||||||
permissions=df.GetPermissions()
|
df.GetPermissions()
|
||||||
df.InsertPermission({
|
df.InsertPermission({
|
||||||
'type': 'anyone',
|
'type': 'anyone',
|
||||||
'value': 'anyone',
|
'value': 'anyone',
|
||||||
@ -1566,15 +1557,15 @@ def feed_unread_books():
|
|||||||
def unread_books(page):
|
def unread_books(page):
|
||||||
return render_read_books(page, False)
|
return render_read_books(page, False)
|
||||||
|
|
||||||
@app.route("/read/<int:book_id>/<format>")
|
@app.route("/read/<int:book_id>/<book_format>")
|
||||||
@login_required_if_no_ano
|
@login_required_if_no_ano
|
||||||
def read_book(book_id, format):
|
def read_book(book_id, book_format):
|
||||||
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()
|
||||||
if book:
|
if book:
|
||||||
book_dir = os.path.join(config.get_main_dir, "cps", "static", str(book_id))
|
book_dir = os.path.join(config.get_main_dir, "cps", "static", str(book_id))
|
||||||
if not os.path.exists(book_dir):
|
if not os.path.exists(book_dir):
|
||||||
os.mkdir(book_dir)
|
os.mkdir(book_dir)
|
||||||
if format.lower() == "epub":
|
if book_format.lower() == "epub":
|
||||||
# check if mimetype file is exists
|
# check if mimetype file is exists
|
||||||
mime_file = str(book_id) + "/mimetype"
|
mime_file = str(book_id) + "/mimetype"
|
||||||
if not os.path.exists(mime_file):
|
if not os.path.exists(mime_file):
|
||||||
@ -1589,9 +1580,7 @@ def read_book(book_id, format):
|
|||||||
try:
|
try:
|
||||||
os.makedirs(newDir)
|
os.makedirs(newDir)
|
||||||
except OSError as exception:
|
except OSError as exception:
|
||||||
if exception.errno == errno.EEXIST:
|
if not exception.errno == errno.EEXIST:
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise
|
raise
|
||||||
if fileName:
|
if fileName:
|
||||||
fd = open(os.path.join(newDir, fileName), "wb")
|
fd = open(os.path.join(newDir, fileName), "wb")
|
||||||
@ -1599,21 +1588,21 @@ def read_book(book_id, format):
|
|||||||
fd.close()
|
fd.close()
|
||||||
zfile.close()
|
zfile.close()
|
||||||
return render_title_template('read.html', bookid=book_id, title=_(u"Read a Book"))
|
return render_title_template('read.html', bookid=book_id, title=_(u"Read a Book"))
|
||||||
elif format.lower() == "pdf":
|
elif book_format.lower() == "pdf":
|
||||||
all_name = str(book_id) + "/" + book.data[0].name + ".pdf"
|
all_name = str(book_id) + "/" + book.data[0].name + ".pdf"
|
||||||
tmp_file = os.path.join(book_dir, book.data[0].name) + ".pdf"
|
tmp_file = os.path.join(book_dir, book.data[0].name) + ".pdf"
|
||||||
if not os.path.exists(tmp_file):
|
if not os.path.exists(tmp_file):
|
||||||
pdf_file = os.path.join(config.config_calibre_dir, book.path, book.data[0].name) + ".pdf"
|
pdf_file = os.path.join(config.config_calibre_dir, book.path, book.data[0].name) + ".pdf"
|
||||||
copyfile(pdf_file, tmp_file)
|
copyfile(pdf_file, tmp_file)
|
||||||
return render_title_template('readpdf.html', pdffile=all_name, title=_(u"Read a Book"))
|
return render_title_template('readpdf.html', pdffile=all_name, title=_(u"Read a Book"))
|
||||||
elif format.lower() == "txt":
|
elif book_format.lower() == "txt":
|
||||||
all_name = str(book_id) + "/" + book.data[0].name + ".txt"
|
all_name = str(book_id) + "/" + book.data[0].name + ".txt"
|
||||||
tmp_file = os.path.join(book_dir, book.data[0].name) + ".txt"
|
tmp_file = os.path.join(book_dir, book.data[0].name) + ".txt"
|
||||||
if not os.path.exists(all_name):
|
if not os.path.exists(all_name):
|
||||||
txt_file = os.path.join(config.config_calibre_dir, book.path, book.data[0].name) + ".txt"
|
txt_file = os.path.join(config.config_calibre_dir, book.path, book.data[0].name) + ".txt"
|
||||||
copyfile(txt_file, tmp_file)
|
copyfile(txt_file, tmp_file)
|
||||||
return render_title_template('readtxt.html', txtfile=all_name, title=_(u"Read a Book"))
|
return render_title_template('readtxt.html', txtfile=all_name, title=_(u"Read a Book"))
|
||||||
elif format.lower() == "cbr":
|
elif book_format.lower() == "cbr":
|
||||||
all_name = str(book_id) + "/" + book.data[0].name + ".cbr"
|
all_name = str(book_id) + "/" + book.data[0].name + ".cbr"
|
||||||
tmp_file = os.path.join(book_dir, book.data[0].name) + ".cbr"
|
tmp_file = os.path.join(book_dir, book.data[0].name) + ".cbr"
|
||||||
if not os.path.exists(all_name):
|
if not os.path.exists(all_name):
|
||||||
@ -1625,13 +1614,13 @@ def read_book(book_id, format):
|
|||||||
flash(_(u"Error opening eBook. File does not exist or file is not accessible:"), category="error")
|
flash(_(u"Error opening eBook. File does not exist or file is not accessible:"), category="error")
|
||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
@app.route("/download/<int:book_id>/<format>")
|
@app.route("/download/<int:book_id>/<book_format>")
|
||||||
@login_required_if_no_ano
|
@login_required_if_no_ano
|
||||||
@download_required
|
@download_required
|
||||||
def get_download_link(book_id, format):
|
def get_download_link(book_id, book_format):
|
||||||
format = format.split(".")[0]
|
book_format = book_format.split(".")[0]
|
||||||
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()
|
||||||
data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == format.upper()).first()
|
data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == book_format.upper()).first()
|
||||||
if data:
|
if data:
|
||||||
# collect downloaded books only for registered user and not for anonymous user
|
# collect downloaded books only for registered user and not for anonymous user
|
||||||
if current_user.is_authenticated:
|
if current_user.is_authenticated:
|
||||||
@ -1640,27 +1629,27 @@ def get_download_link(book_id, format):
|
|||||||
if len(book.authors) > 0:
|
if len(book.authors) > 0:
|
||||||
file_name = book.authors[0].name + '_' + file_name
|
file_name = book.authors[0].name + '_' + file_name
|
||||||
file_name = helper.get_valid_filename(file_name)
|
file_name = helper.get_valid_filename(file_name)
|
||||||
headers={}
|
headers = Headers ()
|
||||||
try:
|
try:
|
||||||
headers["Content-Type"] = mimetypes.types_map['.' + format]
|
headers["Content-Type"] = mimetypes.types_map['.' + book_format]
|
||||||
except:
|
except KeyError:
|
||||||
pass
|
headers["Content-Type"] = "application/octet-stream"
|
||||||
headers["Content-Disposition"] = "attachment; filename*=UTF-8''%s.%s" % (urllib.quote(file_name.encode('utf-8')), format)
|
headers["Content-Disposition"] = "attachment; filename*=UTF-8''%s.%s" % (quote(file_name.encode('utf-8')), book_format)
|
||||||
if config.config_use_google_drive:
|
if config.config_use_google_drive:
|
||||||
df=gdriveutils.getFileFromEbooksFolder(Gdrive.Instance().drive, book.path, '%s.%s' % (data.name, format))
|
df=gdriveutils.getFileFromEbooksFolder(Gdrive.Instance().drive, book.path, '%s.%s' % (data.name, book_format))
|
||||||
return do_gdrive_download(df, headers)
|
return do_gdrive_download(df, headers)
|
||||||
else:
|
else:
|
||||||
response = make_response(send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + format))
|
response = make_response(send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + book_format))
|
||||||
response.headers=headers
|
response.headers=headers
|
||||||
return response
|
return response
|
||||||
else:
|
else:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
@app.route("/download/<int:book_id>/<format>/<anyname>")
|
@app.route("/download/<int:book_id>/<book_format>/<anyname>")
|
||||||
@login_required_if_no_ano
|
@login_required_if_no_ano
|
||||||
@download_required
|
@download_required
|
||||||
def get_download_link_ext(book_id, format, anyname):
|
def get_download_link_ext(book_id, book_format, anyname):
|
||||||
return get_download_link(book_id, format)
|
return get_download_link(book_id, book_format)
|
||||||
|
|
||||||
@app.route('/register', methods=['GET', 'POST'])
|
@app.route('/register', methods=['GET', 'POST'])
|
||||||
def register():
|
def register():
|
||||||
@ -1686,7 +1675,7 @@ def register():
|
|||||||
try:
|
try:
|
||||||
ub.session.add(content)
|
ub.session.add(content)
|
||||||
ub.session.commit()
|
ub.session.commit()
|
||||||
except Exception as e:
|
except Exception:
|
||||||
ub.session.rollback()
|
ub.session.rollback()
|
||||||
flash(_(u"An unknown error occured. Please try again later."), category="error")
|
flash(_(u"An unknown error occured. Please try again later."), category="error")
|
||||||
return render_title_template('register.html', title=_(u"register"))
|
return render_title_template('register.html', title=_(u"register"))
|
||||||
@ -1814,7 +1803,7 @@ def create_shelf():
|
|||||||
ub.session.add(shelf)
|
ub.session.add(shelf)
|
||||||
ub.session.commit()
|
ub.session.commit()
|
||||||
flash(_(u"Shelf %(title)s created", title=to_save["title"]), category="success")
|
flash(_(u"Shelf %(title)s created", title=to_save["title"]), category="success")
|
||||||
except Exception as e:
|
except Exception:
|
||||||
flash(_(u"There was an error"), category="error")
|
flash(_(u"There was an error"), category="error")
|
||||||
return render_title_template('shelf_edit.html', shelf=shelf, title=_(u"create a shelf"))
|
return render_title_template('shelf_edit.html', shelf=shelf, title=_(u"create a shelf"))
|
||||||
else:
|
else:
|
||||||
@ -1842,7 +1831,7 @@ def edit_shelf(shelf_id):
|
|||||||
try:
|
try:
|
||||||
ub.session.commit()
|
ub.session.commit()
|
||||||
flash(_(u"Shelf %(title)s changed", title=to_save["title"]), category="success")
|
flash(_(u"Shelf %(title)s changed", title=to_save["title"]), category="success")
|
||||||
except Exception as e:
|
except Exception:
|
||||||
flash(_(u"There was an error"), category="error")
|
flash(_(u"There was an error"), category="error")
|
||||||
return render_title_template('shelf_edit.html', shelf=shelf, title=_(u"Edit a shelf"))
|
return render_title_template('shelf_edit.html', shelf=shelf, title=_(u"Edit a shelf"))
|
||||||
else:
|
else:
|
||||||
@ -1932,7 +1921,7 @@ def profile():
|
|||||||
try:
|
try:
|
||||||
cur_l = LC.parse(lang.lang_code)
|
cur_l = LC.parse(lang.lang_code)
|
||||||
lang.name = cur_l.get_language_name(get_locale())
|
lang.name = cur_l.get_language_name(get_locale())
|
||||||
except Exception as e:
|
except Exception:
|
||||||
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
||||||
translations = babel.list_translations() + [LC('en')]
|
translations = babel.list_translations() + [LC('en')]
|
||||||
for book in content.downloads:
|
for book in content.downloads:
|
||||||
@ -2146,7 +2135,7 @@ def new_user():
|
|||||||
try:
|
try:
|
||||||
cur_l = LC.parse(lang.lang_code)
|
cur_l = LC.parse(lang.lang_code)
|
||||||
lang.name = cur_l.get_language_name(get_locale())
|
lang.name = cur_l.get_language_name(get_locale())
|
||||||
except Exception as e:
|
except Exception:
|
||||||
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
||||||
translations = [LC('en')] + babel.list_translations()
|
translations = [LC('en')] + babel.list_translations()
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
@ -2251,7 +2240,7 @@ def edit_user(user_id):
|
|||||||
try:
|
try:
|
||||||
cur_l = LC.parse(lang.lang_code)
|
cur_l = LC.parse(lang.lang_code)
|
||||||
lang.name = cur_l.get_language_name(get_locale())
|
lang.name = cur_l.get_language_name(get_locale())
|
||||||
except Exception as e:
|
except Exception:
|
||||||
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
||||||
translations = babel.list_translations() + [LC('en')]
|
translations = babel.list_translations() + [LC('en')]
|
||||||
for book in content.downloads:
|
for book in content.downloads:
|
||||||
@ -2373,17 +2362,17 @@ def edit_book(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)
|
||||||
cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
|
cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
|
||||||
if current_user.filter_language() != "all":
|
if current_user.filter_language() != "all":
|
||||||
filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
lang_filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
||||||
else:
|
else:
|
||||||
filter = True
|
lang_filter = True
|
||||||
book = db.session.query(db.Books).filter(db.Books.id == book_id).filter(filter).first()
|
book = db.session.query(db.Books).filter(db.Books.id == book_id).filter(lang_filter).first()
|
||||||
author_names = []
|
author_names = []
|
||||||
if book:
|
if book:
|
||||||
for index in range(0, len(book.languages)):
|
for index in range(0, len(book.languages)):
|
||||||
try:
|
try:
|
||||||
book.languages[index].language_name = LC.parse(book.languages[index].lang_code).get_language_name(
|
book.languages[index].language_name = LC.parse(book.languages[index].lang_code).get_language_name(
|
||||||
get_locale())
|
get_locale())
|
||||||
except Exception as e:
|
except Exception:
|
||||||
book.languages[index].language_name = _(isoLanguages.get(part3=book.languages[index].lang_code).name)
|
book.languages[index].language_name = _(isoLanguages.get(part3=book.languages[index].lang_code).name)
|
||||||
for author in book.authors:
|
for author in book.authors:
|
||||||
author_names.append(author.name)
|
author_names.append(author.name)
|
||||||
@ -2400,7 +2389,7 @@ def edit_book(book_id):
|
|||||||
modify_database_object(input_authors, book.authors, db.Authors, db.session, 'author')
|
modify_database_object(input_authors, book.authors, db.Authors, db.session, 'author')
|
||||||
if author0_before_edit != book.authors[0].name:
|
if author0_before_edit != book.authors[0].name:
|
||||||
edited_books_id.add(book.id)
|
edited_books_id.add(book.id)
|
||||||
book.author_sort=helper.get_sorted_author(input_authors[0])
|
book.author_sort=helper.get_sorted_author(input_authors[0])
|
||||||
|
|
||||||
if to_save["cover_url"] and os.path.splitext(to_save["cover_url"])[1].lower() == ".jpg":
|
if to_save["cover_url"] and os.path.splitext(to_save["cover_url"])[1].lower() == ".jpg":
|
||||||
img = requests.get(to_save["cover_url"])
|
img = requests.get(to_save["cover_url"])
|
||||||
@ -2441,7 +2430,7 @@ def edit_book(book_id):
|
|||||||
for lang in languages:
|
for lang in languages:
|
||||||
try:
|
try:
|
||||||
lang.name = LC.parse(lang.lang_code).get_language_name(get_locale()).lower()
|
lang.name = LC.parse(lang.lang_code).get_language_name(get_locale()).lower()
|
||||||
except Exception as e:
|
except Exception:
|
||||||
lang.name = _(isoLanguages.get(part3=lang.lang_code).name).lower()
|
lang.name = _(isoLanguages.get(part3=lang.lang_code).name).lower()
|
||||||
for inp_lang in input_languages:
|
for inp_lang in input_languages:
|
||||||
if inp_lang == lang.name:
|
if inp_lang == lang.name:
|
||||||
@ -2578,7 +2567,7 @@ def edit_book(book_id):
|
|||||||
if config.config_use_google_drive:
|
if config.config_use_google_drive:
|
||||||
updateGdriveCalibreFromLocal()
|
updateGdriveCalibreFromLocal()
|
||||||
if "detail_view" in to_save:
|
if "detail_view" in to_save:
|
||||||
return redirect(url_for('show_book', id=book.id))
|
return redirect(url_for('show_book', book_id=book.id))
|
||||||
else:
|
else:
|
||||||
return render_title_template('book_edit.html', book=book, authors=author_names, cc=cc,
|
return render_title_template('book_edit.html', book=book, authors=author_names, cc=cc,
|
||||||
title=_(u"edit metadata"))
|
title=_(u"edit metadata"))
|
||||||
@ -2600,9 +2589,9 @@ def upload():
|
|||||||
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)
|
||||||
db.session.connection().connection.connection.create_function('uuid4', 0, lambda: str(uuid4()))
|
db.session.connection().connection.connection.create_function('uuid4', 0, lambda: str(uuid4()))
|
||||||
if request.method == 'POST' and 'btn-upload' in request.files:
|
if request.method == 'POST' and 'btn-upload' in request.files:
|
||||||
file = request.files['btn-upload']
|
requested_file = request.files['btn-upload']
|
||||||
if '.' in file.filename:
|
if '.' in requested_file.filename:
|
||||||
file_ext = file.filename.rsplit('.', 1)[-1].lower()
|
file_ext = requested_file.filename.rsplit('.', 1)[-1].lower()
|
||||||
if file_ext not in ALLOWED_EXTENSIONS:
|
if file_ext not in ALLOWED_EXTENSIONS:
|
||||||
flash(
|
flash(
|
||||||
_('File extension "%s" is not allowed to be uploaded to this server' %
|
_('File extension "%s" is not allowed to be uploaded to this server' %
|
||||||
@ -2613,7 +2602,7 @@ def upload():
|
|||||||
else:
|
else:
|
||||||
flash(_('File to be uploaded must have an extension'), category="error")
|
flash(_('File to be uploaded must have an extension'), category="error")
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
meta = uploader.upload(file)
|
meta = uploader.upload(requested_file)
|
||||||
|
|
||||||
title = meta.title
|
title = meta.title
|
||||||
author = meta.author
|
author = meta.author
|
||||||
@ -2632,12 +2621,12 @@ def upload():
|
|||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
try:
|
try:
|
||||||
copyfile(meta.file_path, saved_filename)
|
copyfile(meta.file_path, saved_filename)
|
||||||
except OSError as e:
|
except OSError:
|
||||||
flash(_(u"Failed to store file %s (Permission denied)." % saved_filename), category="error")
|
flash(_(u"Failed to store file %s (Permission denied)." % saved_filename), category="error")
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
try:
|
try:
|
||||||
os.unlink(meta.file_path)
|
os.unlink(meta.file_path)
|
||||||
except OSError as e:
|
except OSError:
|
||||||
flash(_(u"Failed to delete file %s (Permission denied)." % meta.file_path), category="warning")
|
flash(_(u"Failed to delete file %s (Permission denied)." % meta.file_path), category="warning")
|
||||||
|
|
||||||
file_size = os.path.getsize(saved_filename)
|
file_size = os.path.getsize(saved_filename)
|
||||||
@ -2653,7 +2642,7 @@ def upload():
|
|||||||
if is_author:
|
if is_author:
|
||||||
db_author = is_author
|
db_author = is_author
|
||||||
else:
|
else:
|
||||||
db_author = db.Authors(author, helper.get_sorted_author(author), "")
|
db_author = db.Authors(author, helper.get_sorted_author(author), "")
|
||||||
db.session.add(db_author)
|
db.session.add(db_author)
|
||||||
|
|
||||||
#add language actually one value in list
|
#add language actually one value in list
|
||||||
@ -2693,16 +2682,18 @@ def upload():
|
|||||||
author_names.append(author.name)
|
author_names.append(author.name)
|
||||||
if config.config_use_google_drive:
|
if config.config_use_google_drive:
|
||||||
updateGdriveCalibreFromLocal()
|
updateGdriveCalibreFromLocal()
|
||||||
cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
|
cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
|
||||||
if current_user.role_edit() or current_user.role_admin():
|
if current_user.role_edit() or current_user.role_admin():
|
||||||
return render_title_template('book_edit.html', book=db_book, authors=author_names, cc=cc,
|
return render_title_template('book_edit.html', book=db_book, authors=author_names, cc=cc,
|
||||||
title=_(u"edit metadata"))
|
title=_(u"edit metadata"))
|
||||||
book_in_shelfs = []
|
book_in_shelfs = []
|
||||||
return render_title_template('detail.html', entry=db_book, cc=cc, title=db_book.title,
|
return render_title_template('detail.html', entry=db_book, cc=cc, title=db_book.title,
|
||||||
books_shelfs=book_in_shelfs, )
|
books_shelfs=book_in_shelfs, )
|
||||||
|
else:
|
||||||
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
def start_gevent():
|
def start_gevent():
|
||||||
from gevent.wsgi import WSGIServer
|
from gevent.wsgi import WSGIServer
|
||||||
global gevent_server
|
global gevent_server
|
||||||
gevent_server = WSGIServer(('', ub.config.config_port), app)
|
gevent_server = WSGIServer(('', ub.config.config_port), app)
|
||||||
gevent_server.serve_forever()
|
gevent_server.serve_forever()
|
||||||
|
Loading…
Reference in New Issue
Block a user