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

# Conflicts:
#	cps/translations/pl/LC_MESSAGES/messages.mo
#	cps/translations/pl/LC_MESSAGES/messages.po
This commit is contained in:
Radosław Kierznowski
2017-03-20 22:01:25 +01:00
1765 changed files with 4324 additions and 316944 deletions

View File

@@ -14,28 +14,28 @@ try:
from wand.image import Image
from wand import version as ImageVersion
use_generic_pdf_cover = False
except ImportError, e:
except ImportError as e:
logger.warning('cannot import Image, generating pdf covers for pdf uploads will not work: %s', e)
use_generic_pdf_cover = True
try:
from PyPDF2 import PdfFileReader
from PyPDF2 import __version__ as PyPdfVersion
use_pdf_meta = True
except ImportError, e:
except ImportError as e:
logger.warning('cannot import PyPDF2, extracting pdf metadata will not work: %s', e)
use_pdf_meta = False
try:
import epub
use_epub_meta = True
except ImportError, e:
except ImportError as e:
logger.warning('cannot import epub, extracting epub metadata will not work: %s', e)
use_epub_meta = False
try:
import fb2
use_fb2_meta = True
except ImportError, e:
except ImportError as e:
logger.warning('cannot import fb2, extracting fb2 metadata will not work: %s', e)
use_fb2_meta = False
@@ -48,7 +48,7 @@ def process(tmp_file_path, original_file_name, original_file_extension):
return epub.get_epub_info(tmp_file_path, original_file_name, original_file_extension)
if ".FB2" == original_file_extension.upper() and use_fb2_meta is True:
return fb2.get_fb2_info(tmp_file_path, original_file_extension)
except Exception, e:
except Exception as e:
logger.warning('cannot parse metadata, using default: %s', e)
return default_meta(tmp_file_path, original_file_name, original_file_extension)
@@ -63,7 +63,8 @@ def default_meta(tmp_file_path, original_file_name, original_file_extension):
description="",
tags="",
series="",
series_id="")
series_id="",
languages="")
def pdf_meta(tmp_file_path, original_file_name, original_file_extension):
@@ -91,7 +92,8 @@ def pdf_meta(tmp_file_path, original_file_name, original_file_extension):
description=subject,
tags="",
series="",
series_id="")
series_id="",
languages="")
def pdf_preview(tmp_file_path, tmp_dir):

View File

@@ -11,10 +11,8 @@ from ub import config
import ub
session = None
cc_exceptions = None
cc_exceptions = ['datetime', 'int', 'comments', 'float', 'composite', 'series']
cc_classes = None
cc_ids = None
books_custom_column_links = None
engine = None
@@ -247,7 +245,7 @@ class Books(Base):
identifiers = relationship('Identifiers', backref='books')
def __init__(self, title, sort, author_sort, timestamp, pubdate, series_index, last_modified, path, has_cover,
authors, tags):
authors, tags, languages = None):
self.title = title
self.sort = sort
self.author_sort = author_sort
@@ -283,22 +281,19 @@ class Custom_Columns(Base):
def setup_db():
global session
global cc_exceptions
global cc_classes
global cc_ids
global books_custom_column_links
global engine
global session
global cc_classes
if config.config_calibre_dir is None or config.config_calibre_dir == u'':
return False
dbpath = os.path.join(config.config_calibre_dir, "metadata.db")
engine = create_engine('sqlite:///{0}'.format(dbpath.encode('utf-8')), echo=False, isolation_level="SERIALIZABLE")
#engine = create_engine('sqlite:///{0}'.format(dbpath.encode('utf-8')), echo=False, isolation_level="SERIALIZABLE")
engine = create_engine('sqlite:///'+ dbpath, echo=False, isolation_level="SERIALIZABLE")
try:
conn = engine.connect()
except:
except Exception as e:
content = ub.session.query(ub.Settings).first()
content.config_calibre_dir = None
content.db_configured = False
@@ -311,43 +306,43 @@ def setup_db():
config.loadSettings()
conn.connection.create_function('title_sort', 1, title_sort)
cc = conn.execute("SELECT id, datatype FROM custom_columns")
if not cc_classes:
cc = conn.execute("SELECT id, datatype FROM custom_columns")
cc_ids = []
cc_exceptions = ['datetime', 'int', 'comments', 'float', 'composite', 'series']
books_custom_column_links = {}
cc_classes = {}
for row in cc:
if row.datatype not in cc_exceptions:
books_custom_column_links[row.id] = Table('books_custom_column_' + str(row.id) + '_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'),
primary_key=True),
Column('value', Integer,
ForeignKey('custom_column_' + str(row.id) + '.id'),
primary_key=True)
)
cc_ids.append([row.id, row.datatype])
if row.datatype == 'bool':
ccdict = {'__tablename__': 'custom_column_' + str(row.id),
'id': Column(Integer, primary_key=True),
'book': Column(Integer, ForeignKey('books.id')),
'value': Column(Boolean)}
cc_ids = []
books_custom_column_links = {}
cc_classes = {}
for row in cc:
if row.datatype not in cc_exceptions:
books_custom_column_links[row.id] = Table('books_custom_column_' + str(row.id) + '_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'),
primary_key=True),
Column('value', Integer,
ForeignKey('custom_column_' + str(row.id) + '.id'),
primary_key=True)
)
cc_ids.append([row.id, row.datatype])
if row.datatype == 'bool':
ccdict = {'__tablename__': 'custom_column_' + str(row.id),
'id': Column(Integer, primary_key=True),
'book': Column(Integer, ForeignKey('books.id')),
'value': Column(Boolean)}
else:
ccdict = {'__tablename__': 'custom_column_' + str(row.id),
'id': Column(Integer, primary_key=True),
'value': Column(String)}
cc_classes[row.id] = type('Custom_Column_' + str(row.id), (Base,), ccdict)
for id in cc_ids:
if id[1] == 'bool':
setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]],
primaryjoin=(
Books.id == cc_classes[id[0]].book),
backref='books'))
else:
ccdict = {'__tablename__': 'custom_column_' + str(row.id),
'id': Column(Integer, primary_key=True),
'value': Column(String)}
cc_classes[row.id] = type('Custom_Column_' + str(row.id), (Base,), ccdict)
for id in cc_ids:
if id[1] == 'bool':
setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]],
primaryjoin=(
Books.id == cc_classes[id[0]].book),
backref='books'))
else:
setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]],
secondary=books_custom_column_links[id[0]],
backref='books'))
setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]],
secondary=books_custom_column_links[id[0]],
backref='books'))
# Base.metadata.create_all(engine)
Session = sessionmaker()

View File

@@ -5,7 +5,7 @@ import zipfile
from lxml import etree
import os
import uploader
from iso639 import languages as isoLanguages
def extractCover(zip, coverFile, coverpath, tmp_file_name):
if coverFile is None:
@@ -41,23 +41,53 @@ def get_epub_info(tmp_file_path, original_file_name, original_file_extension):
p = tree.xpath('/pkg:package/pkg:metadata', namespaces=ns)[0]
epub_metadata = {}
for s in ['title', 'description', 'creator']:
for s in ['title', 'description', 'creator', 'language']:
tmp = p.xpath('dc:%s/text()' % s, namespaces=ns)
if len(tmp) > 0:
epub_metadata[s] = p.xpath('dc:%s/text()' % s, namespaces=ns)[0]
else:
epub_metadata[s] = "Unknown"
if epub_metadata['description'] == "Unknown":
description = tree.xpath("//*[local-name() = 'description']/text()")
if len(description) > 0:
epub_metadata['description'] = description
else:
epub_metadata['description'] = ""
if epub_metadata['language'] == "Unknown":
epub_metadata['language'] == ""
else:
lang = epub_metadata['language'].split('-', 1)[0].lower()
if len(lang) == 2:
epub_metadata['language'] = isoLanguages.get(part1=lang).name
elif len(lang) == 3:
epub_metadata['language'] = isoLanguages.get(part3=lang).name
else:
epub_metadata['language'] = ""
coversection = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='cover-image']/@href", namespaces=ns)
coverfile = None
if len(coversection) > 0:
coverfile = extractCover(zip, coversection[0], coverpath, tmp_file_path)
else:
coversection = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='cover']/@href", namespaces=ns)
if len(coversection) > 0:
coverfile = extractCover(zip, coversection[0], coverpath, tmp_file_path)
else:
coverfile = None
meta_cover = tree.xpath("/pkg:package/pkg:metadata/pkg:meta[@name='cover']/@content", namespaces=ns)
if len(meta_cover) > 0:
coversection = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='"+meta_cover[0]+"']/@href", namespaces=ns)
if len(coversection) > 0:
filetype = coversection[0].rsplit('.',1)[-1]
if filetype == "xhtml" or filetype == "html": #if cover is (x)html format
markup = zip.read(os.path.join(coverpath,coversection[0]))
markupTree = etree.fromstring(markup)
#no matter xhtml or html with no namespace
imgsrc = markupTree.xpath("//*[local-name() = 'img']/@src")
#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]))
coverfile = extractCover(zip, filename, "", tmp_file_path)
else:
coverfile = extractCover(zip, coversection[0], coverpath, tmp_file_path)
if epub_metadata['title'] is None:
title = original_file_name
else:
@@ -72,4 +102,5 @@ def get_epub_info(tmp_file_path, original_file_name, original_file_extension):
description=epub_metadata['description'],
tags="",
series="",
series_id="")
series_id="",
languages=epub_metadata['language'])

View File

@@ -4,8 +4,10 @@
from lxml import etree
import os
import uploader
import StringIO
try:
from io import StringIO
except ImportError as e:
import StringIO
def get_fb2_info(tmp_file_path, original_file_extension):
@@ -37,16 +39,16 @@ def get_fb2_info(tmp_file_path, original_file_extension):
first_name = u''
return first_name + ' ' + middle_name + ' ' + last_name
author = unicode(", ".join(map(get_author, authors)))
author = str(", ".join(map(get_author, authors)))
title = tree.xpath('/fb:FictionBook/fb:description/fb:title-info/fb:book-title/text()', namespaces=ns)
if len(title):
title = unicode(title[0])
title = str(title[0])
else:
title = u''
description = tree.xpath('/fb:FictionBook/fb:description/fb:publish-info/fb:book-name/text()', namespaces=ns)
if len(description):
description = unicode(description[0])
description = str(description[0])
else:
description = u''
@@ -59,4 +61,5 @@ def get_fb2_info(tmp_file_path, original_file_extension):
description=description,
tags="",
series="",
series_id="")
series_id="",
languages="")

370
cps/gdriveutils.py Normal file
View File

@@ -0,0 +1,370 @@
try:
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from apiclient import errors
except ImportError:
pass
import os, time
from ub import config
from sqlalchemy import *
from sqlalchemy import exc
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import *
import web
dbpath = os.path.join(os.path.normpath(os.path.dirname(os.path.realpath(__file__)) + os.sep + ".." + os.sep), "gdrive.db")
engine = create_engine('sqlite:///{0}'.format(dbpath), echo=False)
Base = declarative_base()
# Open session for database connection
Session = sessionmaker()
Session.configure(bind=engine)
session = scoped_session(Session)
class GdriveId(Base):
__tablename__='gdrive_ids'
id = Column(Integer, primary_key=True)
gdrive_id = Column(Integer, unique=True)
path = Column(String)
__table_args__ = (UniqueConstraint('gdrive_id', 'path', name='_gdrive_path_uc'),)
def __repr__(self):
return str(self.path)
class PermissionAdded(Base):
__tablename__='permissions_added'
id = Column(Integer, primary_key=True)
gdrive_id = Column(Integer, unique=True)
def __repr__(self):
return str(self.gdrive_id)
def migrate():
if not engine.dialect.has_table(engine.connect(), "permissions_added"):
PermissionAdded.__table__.create(bind = engine)
for sql in session.execute("select sql from sqlite_master where type='table'"):
if 'CREATE TABLE gdrive_ids' in sql[0]:
currUniqueConstraint='UNIQUE (gdrive_id)'
if currUniqueConstraint in sql[0]:
sql=sql[0].replace(currUniqueConstraint, 'UNIQUE (gdrive_id, path)')
sql=sql.replace(GdriveId.__tablename__, GdriveId.__tablename__+ '2')
session.execute(sql)
session.execute('INSERT INTO gdrive_ids2 (id, gdrive_id, path) SELECT id, gdrive_id, path FROM gdrive_ids;')
session.commit()
session.execute('DROP TABLE %s' % 'gdrive_ids')
session.execute('ALTER TABLE gdrive_ids2 RENAME to gdrive_ids')
break
if not os.path.exists(dbpath):
try:
Base.metadata.create_all(engine)
except Exception:
raise
migrate()
def getDrive(gauth=None):
if not gauth:
gauth=GoogleAuth(settings_file='settings.yaml')
# Try to load saved client credentials
gauth.LoadCredentialsFile("gdrive_credentials")
if gauth.access_token_expired:
# Refresh them if expired
gauth.Refresh()
else:
# Initialize the saved creds
gauth.Authorize()
# Save the current credentials to a file
return GoogleDrive(gauth)
def getEbooksFolder(drive=None):
if not drive:
drive = getDrive()
if drive.auth.access_token_expired:
drive.auth.Refresh()
ebooksFolder= "title = '%s' and 'root' in parents and mimeType = 'application/vnd.google-apps.folder' and trashed = false" % config.config_google_drive_folder
fileList = drive.ListFile({'q': ebooksFolder}).GetList()
return fileList[0]
def getEbooksFolderId(drive=None):
storedPathName=session.query(GdriveId).filter(GdriveId.path == '/').first()
if storedPathName:
return storedPathName.gdrive_id
else:
gDriveId=GdriveId()
gDriveId.gdrive_id=getEbooksFolder(drive)['id']
gDriveId.path='/'
session.merge(gDriveId)
session.commit()
return
def getFolderInFolder(parentId, folderName, drive=None):
if not drive:
drive = getDrive()
if drive.auth.access_token_expired:
drive.auth.Refresh()
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()
return fileList[0]
def getFile(pathId, fileName, drive=None):
if not drive:
drive = getDrive()
if drive.auth.access_token_expired:
drive.auth.Refresh()
metaDataFile="'%s' in parents and trashed = false and title = '%s'" % (pathId, fileName.replace("'", "\\'"))
fileList = drive.ListFile({'q': metaDataFile}).GetList()
return fileList[0]
def getFolderId(path, drive=None):
if not drive:
drive=getDrive()
if drive.auth.access_token_expired:
drive.auth.Refresh()
currentFolderId=getEbooksFolderId(drive)
sqlCheckPath=path if path[-1] =='/' else path + '/'
storedPathName=session.query(GdriveId).filter(GdriveId.path == sqlCheckPath).first()
if not storedPathName:
dbChange=False
s=path.split('/')
for i, x in enumerate(s):
if len(x) > 0:
currentPath="/".join(s[:i+1])
if currentPath[-1] != '/':
currentPath = currentPath + '/'
storedPathName=session.query(GdriveId).filter(GdriveId.path == currentPath).first()
if storedPathName:
currentFolderId=storedPathName.gdrive_id
else:
currentFolderId=getFolderInFolder(currentFolderId, x, drive)['id']
gDriveId=GdriveId()
gDriveId.gdrive_id=currentFolderId
gDriveId.path=currentPath
session.merge(gDriveId)
dbChange=True
if dbChange:
session.commit()
else:
currentFolderId=storedPathName.gdrive_id
return currentFolderId
def getFileFromEbooksFolder(drive, path, fileName):
if not drive:
drive=getDrive()
if drive.auth.access_token_expired:
drive.auth.Refresh()
if path:
sqlCheckPath=path if path[-1] =='/' else path + '/'
folderId=getFolderId(path, drive)
else:
folderId=getEbooksFolderId(drive)
return getFile(folderId, fileName, drive)
def copyDriveFileRemote(drive, origin_file_id, copy_title):
if not drive:
drive=getDrive()
if drive.auth.access_token_expired:
drive.auth.Refresh()
copied_file = {'title': copy_title}
try:
file_data = drive.auth.service.files().copy(
fileId=origin_file_id, body=copied_file).execute()
return drive.CreateFile({'id': file_data['id']})
except errors.HttpError as error:
print ('An error occurred: %s' % error)
return None
def downloadFile(drive, path, filename, output):
if not drive:
drive=getDrive()
if drive.auth.access_token_expired:
drive.auth.Refresh()
f=getFileFromEbooksFolder(drive, path, filename)
f.GetContentFile(output)
def backupCalibreDbAndOptionalDownload(drive, f=None):
pass
if not drive:
drive=getDrive()
if drive.auth.access_token_expired:
drive.auth.Refresh()
metaDataFile="'%s' in parents and title = 'metadata.db' and trashed = false" % getEbooksFolderId()
fileList = drive.ListFile({'q': metaDataFile}).GetList()
databaseFile=fileList[0]
if f:
databaseFile.GetContentFile(f)
def copyToDrive(drive, uploadFile, createRoot, replaceFiles,
ignoreFiles=[],
parent=None, prevDir=''):
if not drive:
drive=getDrive()
if drive.auth.access_token_expired:
drive.auth.Refresh()
isInitial=not bool(parent)
if not parent:
parent=getEbooksFolder(drive)
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()
if len(existingFolder) == 0 and (not isInitial or createRoot):
parent = drive.CreateFile({'title': os.path.basename(uploadFile), 'parents' : [{"kind": "drive#fileLink", 'id' : parent['id']}],
"mimeType": "application/vnd.google-apps.folder" })
parent.Upload()
else:
if (not isInitial or createRoot) and len(existingFolder) > 0:
parent=existingFolder[0]
for f in os.listdir(os.path.join(prevDir,uploadFile)):
if f not in ignoreFiles:
copyToDrive(drive, f, True, replaceFiles, ignoreFiles, parent, os.path.join(prevDir,uploadFile))
else:
if os.path.basename(uploadFile) not in ignoreFiles:
existingFiles=drive.ListFile({'q' : "title = '%s' and '%s' in parents and trashed = false" % (os.path.basename(uploadFile), parent['id'])}).GetList()
if len(existingFiles) > 0:
driveFile=existingFiles[0]
else:
driveFile = drive.CreateFile({'title': os.path.basename(uploadFile), 'parents' : [{"kind": "drive#fileLink", 'id' : parent['id']}], })
driveFile.SetContentFile(os.path.join(prevDir,uploadFile))
driveFile.Upload()
def uploadFileToEbooksFolder(drive, destFile, f):
if not drive:
drive=getDrive()
if drive.auth.access_token_expired:
drive.auth.Refresh()
parent=getEbooksFolder(drive)
splitDir=destFile.split('/')
for i, x in enumerate(splitDir):
if i == len(splitDir)-1:
existingFiles=drive.ListFile({'q' : "title = '%s' and '%s' in parents and trashed = false" % (x, parent['id'])}).GetList()
if len(existingFiles) > 0:
driveFile=existingFiles[0]
else:
driveFile = drive.CreateFile({'title': x, 'parents' : [{"kind": "drive#fileLink", 'id' : parent['id']}], })
driveFile.SetContentFile(f)
driveFile.Upload()
else:
existingFolder=drive.ListFile({'q' : "title = '%s' and '%s' in parents and trashed = false" % (x, parent['id'])}).GetList()
if len(existingFolder) == 0:
parent = drive.CreateFile({'title': x, 'parents' : [{"kind": "drive#fileLink", 'id' : parent['id']}],
"mimeType": "application/vnd.google-apps.folder" })
parent.Upload()
else:
parent=existingFolder[0]
def watchChange(drive, channel_id, channel_type, channel_address,
channel_token=None, expiration=None):
if not drive:
drive=getDrive()
if drive.auth.access_token_expired:
drive.auth.Refresh()
"""Watch for all changes to a user's Drive.
Args:
service: Drive API service instance.
channel_id: Unique string that identifies this channel.
channel_type: Type of delivery mechanism used for this channel.
channel_address: Address where notifications are delivered.
channel_token: An arbitrary string delivered to the target address with
each notification delivered over this channel. Optional.
channel_address: Address where notifications are delivered. Optional.
Returns:
The created channel if successful
Raises:
apiclient.errors.HttpError: if http request to create channel fails.
"""
body = {
'id': channel_id,
'type': channel_type,
'address': channel_address
}
if channel_token:
body['token'] = channel_token
if expiration:
body['expiration'] = expiration
return drive.auth.service.changes().watch(body=body).execute()
def watchFile(drive, file_id, channel_id, channel_type, channel_address,
channel_token=None, expiration=None):
"""Watch for any changes to a specific file.
Args:
service: Drive API service instance.
file_id: ID of the file to watch.
channel_id: Unique string that identifies this channel.
channel_type: Type of delivery mechanism used for this channel.
channel_address: Address where notifications are delivered.
channel_token: An arbitrary string delivered to the target address with
each notification delivered over this channel. Optional.
channel_address: Address where notifications are delivered. Optional.
Returns:
The created channel if successful
Raises:
apiclient.errors.HttpError: if http request to create channel fails.
"""
if not drive:
drive=getDrive()
if drive.auth.access_token_expired:
drive.auth.Refresh()
body = {
'id': channel_id,
'type': channel_type,
'address': channel_address
}
if channel_token:
body['token'] = channel_token
if expiration:
body['expiration'] = expiration
return drive.auth.service.files().watch(fileId=file_id, body=body).execute()
def stopChannel(drive, channel_id, resource_id):
"""Stop watching to a specific channel.
Args:
service: Drive API service instance.
channel_id: ID of the channel to stop.
resource_id: Resource ID of the channel to stop.
Raises:
apiclient.errors.HttpError: if http request to create channel fails.
"""
if not drive:
drive=getDrive()
if drive.auth.access_token_expired:
drive.auth.Refresh()
service=drive.auth.service
body = {
'id': channel_id,
'resourceId': resource_id
}
return drive.auth.service.channels().stop(body=body).execute()
def getChangeById (drive, change_id):
if not drive:
drive=getDrive()
if drive.auth.access_token_expired:
drive.auth.Refresh()
"""Print a single Change resource information.
Args:
service: Drive API service instance.
change_id: ID of the Change resource to retrieve.
"""
try:
change = drive.auth.service.changes().get(changeId=change_id).execute()
return change
except errors.HttpError, error:
web.app.logger.exception(error)
return None

View File

@@ -13,11 +13,18 @@ import os
import traceback
import re
import unicodedata
from StringIO import StringIO
try:
from StringIO import StringIO
from email.MIMEBase import MIMEBase
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
except ImportError as e:
from io import StringIO
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email import encoders
from email.MIMEBase import MIMEBase
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.generator import Generator
from email.utils import formatdate
from email.utils import make_msgid
@@ -28,11 +35,16 @@ import shutil
import requests
import zipfile
from tornado.ioloop import IOLoop
try:
import gdriveutils as gd
except ImportError:
pass
import web
try:
import unidecode
use_unidecode=True
except:
except Exception as e:
use_unidecode=False
# Global variables
@@ -147,7 +159,7 @@ def send_raw_email(kindle_mail, msg):
smtplib.stderr = org_stderr
except (socket.error, smtplib.SMTPRecipientsRefused, smtplib.SMTPException), e:
except (socket.error, smtplib.SMTPRecipientsRefused, smtplib.SMTPException) as e:
app.logger.error(traceback.print_exc())
return _("Failed to send mail: %s" % str(e))
@@ -239,7 +251,10 @@ def get_valid_filename(value, replace_whitespace=True):
value=value.replace(u'ß',u'ss')
value = unicodedata.normalize('NFKD', value)
re_slugify = re.compile('[\W\s-]', re.UNICODE)
value = unicode(re_slugify.sub('', value).strip())
if type(value) is str: #Python3 str, Python2 unicode
value = re_slugify.sub('', value).strip()
else:
value = unicode(re_slugify.sub('', value).strip())
if replace_whitespace:
#*+:\"/<>? werden durch _ ersetzt
value = re.sub('[\*\+:\\\"/<>\?]+', u'_', value, flags=re.U)
@@ -280,6 +295,30 @@ def update_dir_stucture(book_id, calibrepath):
book.path = new_authordir + '/' + book.path.split('/')[1]
db.session.commit()
def update_dir_structure_gdrive(book_id):
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()
authordir = book.path.split('/')[0]
new_authordir = get_valid_filename(book.authors[0].name)
titledir = book.path.split('/')[1]
new_titledir = get_valid_filename(book.title) + " (" + str(book_id) + ")"
if titledir != new_titledir:
print (titledir)
gFile=gd.getFileFromEbooksFolder(web.Gdrive.Instance().drive,os.path.dirname(book.path),titledir)
gFile['title']= new_titledir
gFile.Upload()
book.path = book.path.split('/')[0] + '/' + new_titledir
if authordir != new_authordir:
gFile=gd.getFileFromEbooksFolder(web.Gdrive.Instance().drive,None,authordir)
gFile['title']= new_authordir
gFile.Upload()
book.path = new_authordir + '/' + book.path.split('/')[1]
db.session.commit()
class Updater(threading.Thread):
def __init__(self):
@@ -305,9 +344,13 @@ class Updater(threading.Thread):
ub.session.close()
ub.engine.dispose()
self.status=6
# stop tornado server
server = IOLoop.instance()
server.add_callback(server.stop)
if web.gevent_server:
web.gevent_server.stop()
else:
# stop tornado server
server = IOLoop.instance()
server.add_callback(server.stop)
self.status=7
def get_update_status(self):
@@ -379,7 +422,7 @@ class Updater(threading.Thread):
try:
os.chown(dst_file, permission.st_uid, permission.st_uid)
# print('Permissions: User '+str(new_permissions.st_uid)+' Group '+str(new_permissions.st_uid))
except:
except Exception as e:
e = sys.exc_info()
logging.getLogger('cps.web').debug('Fail '+str(dst_file)+' error: '+str(e))
return
@@ -421,7 +464,7 @@ class Updater(threading.Thread):
logging.getLogger('cps.web').debug("Delete file " + item_path)
log_from_thread("Delete file " + item_path)
os.remove(item_path)
except:
except Exception as e:
logging.getLogger('cps.web').debug("Could not remove:" + item_path)
shutil.rmtree(source, ignore_errors=True)

180
cps/static/js/get_meta.js Normal file
View File

@@ -0,0 +1,180 @@
/*
* Get Metadata from Douban Books api and Google Books api
* Created by idalin<dalin.lin@gmail.com>
* 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)
*/
$(document).ready(function () {
var msg = i18n_msg;
var douban = 'https://api.douban.com';
var db_search = '/v2/book/search';
var db_get_info = '/v2/book/';
var db_get_info_by_isbn = '/v2/book/isbn/ ';
var db_done = false;
var google = 'https://www.googleapis.com/';
var gg_search = '/books/v1/volumes';
var gg_get_info = '/books/v1/volumes/';
var gg_done = false;
var db_results = [];
var gg_results = [];
var show_flag = 0;
String.prototype.replaceAll = function (s1, s2) {  
return this.replace(new RegExp(s1, "gm"), s2);  
}
gg_search_book = function (title) {
title = title.replaceAll(/\s+/, '+');
var url = google + gg_search + '?q=' + title;
$.ajax({
url: url,
type: "GET",
dataType: "jsonp",
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') {
meta = db_results[id];
$('#description').val(meta.summary);
$('#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;
}
}
if (gg_done && gg_results.length > 0) {
for (var i = 0; i < gg_results.length; i++) {
var book = gg_results[i];
var book_cover;
if (book.volumeInfo.imageLinks) {
book_cover = book.volumeInfo.imageLinks.thumbnail;
} else {
book_cover = '/static/generic_cover.jpg';
}
var book_html = '<li class="media">' +
'<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",' +
i + ')\'>' +
'<div class="media-body">' +
'<h4 class="media-heading"><a href="https://books.google.com/books?id=' +
book.id + '" target="_blank">' + book.volumeInfo.title + '</a></h4>' +
'<p>'+ msg.author +'' + book.volumeInfo.authors + '</p>' +
'<p>'+ msg.publisher + '' + book.volumeInfo.publisher + '</p>' +
'<p>'+ msg.description + ':' + book.volumeInfo.description + '</p>' +
'<p>'+ msg.source + ':<a href="https://books.google.com" target="_blank">Google Books</a></p>' +
'</div>' +
'</li>';
$("#book-list").append(book_html);
}
gg_done = false;
}
if (db_done && db_results.length > 0) {
for (var i = 0; i < db_results.length; i++) {
var book = db_results[i];
var book_html = '<li class="media">' +
'<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",' +
i + ')\'>' +
'<div class="media-body">' +
'<h4 class="media-heading"><a href="https://book.douban.com/subject/' +
book.id + '" target="_blank">' + book.title + '</a></h4>' +
'<p>' + msg.author + '' + book.author + '</p>' +
'<p>' + msg.publisher + '' + book.publisher + '</p>' +
'<p>' + msg.description + ':' + book.summary + '</p>' +
'<p>' + msg.source + ':<a href="https://book.douban.com" target="_blank">Douban Books</a></p>' +
'</div>' +
'</li>';
$("#book-list").append(book_html);
}
db_done = false;
}
}
$('#do-search').click(function () {
var keyword = $('#keyword').val();
if (keyword) {
do_search(keyword);
}
});
$('#get_meta').click(function () {
var book_title = $('#book_title').val();
if (book_title) {
$('#keyword').val(book_title);
do_search(book_title);
}
});
});

View File

@@ -0,0 +1 @@
!function(a){"use strict";function b(a){return"[data-value"+(a?"="+a:"")+"]"}function c(a,b,c){var d=c.activeIcon,e=c.inactiveIcon;a.removeClass(b?e:d).addClass(b?d:e)}function d(b,c){var d=a.extend({},i,b.data(),c);return d.inline=""===d.inline||d.inline,d.readonly=""===d.readonly||d.readonly,d.clearable===!1?d.clearableLabel="":d.clearableLabel=d.clearable,d.clearable=""===d.clearable||d.clearable,d}function e(b,c){if(c.inline)var d=a('<span class="rating-input"></span>');else var d=a('<div class="rating-input"></div>');d.addClass(b.attr("class")),d.removeClass("rating");for(var e=c.min;e<=c.max;e++)d.append('<i class="'+c.iconLib+'" data-value="'+e+'"></i>');return c.clearable&&!c.readonly&&d.append("&nbsp;").append('<a class="'+f+'"><i class="'+c.iconLib+" "+c.clearableIcon+'"/>'+c.clearableLabel+"</a>"),d}var f="rating-clear",g="."+f,h="hidden",i={min:1,max:5,"empty-value":0,iconLib:"glyphicon",activeIcon:"glyphicon-star",inactiveIcon:"glyphicon-star-empty",clearable:!1,clearableIcon:"glyphicon-remove",clearableRemain:!1,inline:!1,readonly:!1},j=function(a,b){var c=this.$input=a;this.options=d(c,b);var f=this.$el=e(c,this.options);c.addClass(h).before(f),c.attr("type","hidden"),this.highlight(c.val())};j.VERSION="0.4.0",j.DEFAULTS=i,j.prototype={clear:function(){this.setValue(this.options["empty-value"])},setValue:function(a){this.highlight(a),this.updateInput(a)},highlight:function(a,d){var e=this.options,f=this.$el;if(a>=this.options.min&&a<=this.options.max){var i=f.find(b(a));c(i.prevAll("i").andSelf(),!0,e),c(i.nextAll("i"),!1,e)}else c(f.find(b()),!1,e);d||(this.options.clearableRemain?f.find(g).removeClass(h):a&&a!=this.options["empty-value"]?f.find(g).removeClass(h):f.find(g).addClass(h))},updateInput:function(a){var b=this.$input;b.val()!=a&&b.val(a).change()}};var k=a.fn.rating=function(c){return this.filter("input[type=number]").each(function(){var d=a(this),e="object"==typeof c&&c||{},f=new j(d,e);f.options.readonly||f.$el.on("mouseenter",b(),function(){f.highlight(a(this).data("value"),!0)}).on("mouseleave",b(),function(){f.highlight(d.val(),!0)}).on("click",b(),function(){f.setValue(a(this).data("value"))}).on("click",g,function(){f.clear()})})};k.Constructor=j,a(function(){a("input.rating[type=number]").each(function(){a(this).rating()})})}(jQuery);

1277
cps/static/js/libs/jquery.form.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -65,6 +65,13 @@ $(function() {
}
});
});
$("#restart_database").click(function() {
$.ajax({
dataType: 'json',
url: window.location.pathname+"/../../shutdown",
data: {"parameter":2}
});
});
$("#perform_update").click(function() {
$('#spinner2').show();
$.ajax({

View File

@@ -80,6 +80,7 @@
<div>{{_('Current commit timestamp')}}: <span>{{commit}} </span></div>
<div class="hidden" id="update_info">{{_('Newest commit timestamp')}}: <span></span></div>
<p></p>
<div class="btn btn-default" id="restart_database">{{_('Reconnect to Calibre DB')}}</div>
<div class="btn btn-default" data-toggle="modal" data-target="#RestartDialog">{{_('Restart Calibre-web')}}</div>
<div class="btn btn-default" data-toggle="modal" data-target="#ShutdownDialog">{{_('Stop Calibre-web')}}</div>
<div class="btn btn-default" id="check_for_update">{{_('Check for update')}}</div>

View File

@@ -39,7 +39,7 @@
</div>
<div class="form-group">
<label for="rating">{{_('Rating')}}</label>
<input type="number" min="0" max="5" step="1" class="form-control" name="rating" id="rating" value="{% if book.ratings %}{{book.ratings[0].rating / 2}}{% endif %}">
<input type="number" name="rating" id="rating" class="rating input-lg" data-clearable="" value="{% if book.ratings %}{{(book.ratings[0].rating / 2)|int}}{% endif %}">
</div>
<div class="form-group">
<label for="cover_url">{{_('Cover URL (jpg)')}}</label>
@@ -104,16 +104,54 @@
<input name="detail_view" type="checkbox" checked> {{_('view book after edit')}}
</label>
</div>
<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>
<a href="{{ url_for('show_book',id=book.id) }}" class="btn btn-default">{{_('Back')}}</a>
</form>
</div>
{% endif %}
<div class="modal fade" id="metaModal" tabindex="-1" role="dialog" aria-labelledby="metaModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="metaModalLabel">{{_('Get metadata')}}</h4>
<form class="form-inline">
<div class="form-group">
<label class="sr-only" for="keyword">{{_('Keyword')}}</label>
<input type="text" class="form-control" id="keyword" placeholder="{{_(" Search keyword ")}}">
</div>
<button type="button" class="btn btn-default" id="do-search">{{_("Go!")}}</button>
<span>{{_('Click the cover to load metadata to the form')}}</span>
</form>
</div>
<div class="modal-body" id="meta-info">
{{_("Loading...")}}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{_('Close')}}</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script>
var i18n_msg = {
'loading': {{_('Loading...')|safe|tojson}},
'search_error': {{_('Search error!')|safe|tojson}},
'no_result': {{_('No Result! Please try anonther keyword.')|safe|tojson}},
'author': {{_('Author')|safe|tojson}},
'publisher': {{_('Publisher')|safe|tojson}},
'description': {{_('Description')|safe|tojson}},
'source': {{_('Source')|safe|tojson}},
};
</script>
<script src="{{ url_for('static', filename='js/libs/typeahead.bundle.js') }}"></script>
<script src="{{ url_for('static', filename='js/edit_books.js') }}"></script>
<script src="{{ url_for('static', filename='js/libs/bootstrap-rating-input.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/get_meta.js') }}"></script>
{% endblock %}
{% block header %}
<link href="{{ url_for('static', filename='css/libs/typeahead.css') }}" rel="stylesheet" media="screen">

View File

@@ -7,6 +7,47 @@
<label for="config_calibre_dir">{{_('Location of Calibre database')}}</label>
<input type="text" class="form-control" name="config_calibre_dir" id="config_calibre_dir" value="{% if content.config_calibre_dir != None %}{{ content.config_calibre_dir }}{% endif %}" autocomplete="off">
</div>
{% if gdrive %}
<div class="form-group required">
<input type="checkbox" id="config_use_google_drive" name="config_use_google_drive" {% if content.config_use_google_drive %}checked{% endif %} >
<label for="config_use_google_drive">{{_('Use google drive?')}}</label>
</div>
<div id="gdrive_settings">
<div class="form-group required">
<label for="config_google_drive_client_id">{{_('Client id')}}</label>
<input type="text" class="form-control" name="config_google_drive_client_id" id="config_google_drive_client_id" value="{% if content.config_google_drive_client_id %}{{content.config_google_drive_client_id}}{% endif %}" autocomplete="off">
</div>
<div class="form-group required">
<label for="config_google_drive_client_secret">{{_('Client secret')}}</label>
<input type="text" class="form-control" name="config_google_drive_client_secret" id="config_google_drive_client_secret" value="{% if content.config_google_drive_client_secret %}{{content.config_google_drive_client_secret}}{% endif %}" autocomplete="off">
</div>
<div class="form-group required">
<label for="config_google_drive_calibre_url_base">{{_('Calibre Base URL')}}</label>
<input type="text" class="form-control" name="config_google_drive_calibre_url_base" id="config_google_drive_calibre_url_base" value="{% if content.config_google_drive_calibre_url_base %}{{content.config_google_drive_calibre_url_base}}{% endif %}" autocomplete="off">
</div>
<div class="form-group required">
<label for="config_google_drive_folder">{{_('Google drive Calibre folder')}}</label>
<input type="text" class="form-control" name="config_google_drive_folder" id="config_google_drive_folder" value="{% if content.config_google_drive_folder %}{{content.config_google_drive_folder}}{% endif %}" autocomplete="off" required>
</div>
{% if show_authenticate_google_drive %}
<div class="form-group required">
<a href="{{ url_for('authenticate_google_drive') }}" class="btn btn-primary">Authenticate Google Drive</a>
</div>
{% else %}
{% if content.config_google_drive_watch_changes_response %}
<label for="config_google_drive_watch_changes_response">{{_('Metadata Watch Channel ID')}}</label>
<div class="form-group input-group required">
<input type="text" class="form-control" name="config_google_drive_watch_changes_response" id="config_google_drive_watch_changes_response" value="{{ content.config_google_drive_watch_changes_response['id'] }} expires on {{ content.config_google_drive_watch_changes_response['expiration'] | strftime }}" autocomplete="off" disabled="">
<span class="input-group-btn">
<a href="{{ url_for('revoke_watch_gdrive') }}" class="btn btn-primary">Revoke</a>
</span>
{% else %}
<a href="{{ url_for('watch_gdrive') }}" class="btn btn-primary">Enable watch of metadata.db</a>
{% endif %}
</div>
{% endif %}
</div>
{% endif %}
<div class="form-group">
<label for="config_port">{{_('Server Port')}}</label>
<input type="number" min="1" max="65535" class="form-control" name="config_port" id="config_port" value="{% if content.config_port != None %}{{ content.config_port }}{% endif %}" autocomplete="off" required>
@@ -23,7 +64,10 @@
<label for="config_random_books">{{_('No. of random books to show')}}</label>
<input type="number" min="1" max="30" class="form-control" name="config_random_books" id="config_random_books" value="{% if content.config_random_books != None %}{{ content.config_random_books }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<label for="config_columns_to_ignore">{{_('Regular expression for ignoring columns')}}</label>
<input type="text" class="form-control" name="config_columns_to_ignore" id="config_columns_to_ignore" value="{% if content.config_columns_to_ignore != None %}{{ content.config_columns_to_ignore }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<label for="config_title_regex">{{_('Regular expression for title sorting')}}</label>
<input type="text" class="form-control" name="config_title_regex" id="config_title_regex" value="{% if content.config_title_regex != None %}{{ content.config_title_regex }}{% endif %}" autocomplete="off">
@@ -70,6 +114,10 @@
<input type="checkbox" name="passwd_role" id="passwd_role" {% if content.role_passwd() %}checked{% endif %}>
<label for="passwd_role">{{_('Allow Changing Password')}}</label>
</div>
<div class="form-group">
<input type="checkbox" name="edit_shelf_role" id="edit_shelf_role" {% if content.role_edit_shelfs() %}checked{% endif %}>
<label for="passwd_role">{{_('Allow Editing Public Shelfs')}}</label>
</div>
<button type="submit" class="btn btn-default">{{_('Submit')}}</button>
{% if not origin %}
<a href="{{ url_for('admin') }}" class="btn btn-default">{{_('Back')}}</a>
@@ -80,3 +128,22 @@
</form>
</div>
{% endblock %}
{% block js %}
<script>
$(document).ready(function() {
$('#config_use_google_drive').trigger("change");
});
$('#config_use_google_drive').change(function(){
formInputs=$("#gdrive_settings :input");
isChecked=this.checked;
formInputs.each(function(formInput) {
$(this).prop('required',isChecked);
});
if (this.checked) {
$('#gdrive_settings').show();
} else {
$('#gdrive_settings').hide();
}
});
</script>
{% endblock %}

View File

@@ -2,7 +2,7 @@
{% block body %}
<div class="single">
<div class="row">
<div class="col-sm-3 col-lg-3 col-xs-12">
<div class="col-sm-3 col-lg-3 col-xs-5">
<div class="cover">
{% if entry.has_cover %}
<img src="{{ url_for('get_cover', cover_path=entry.path.replace('\\','/')) }}" />
@@ -107,6 +107,16 @@
</div>
</p>
{% endif %}
{% if not g.user.is_anonymous() %}
<p>
<div class="custom_columns" id="have_read_container">
<form id="have_read_form" action="{{ url_for('toggle_read', id=entry.id)}}" method="POST") >
<input id="have_read_cb" type="checkbox" {% if have_read %}checked{% endif %} >
<label for="have_read_cb">{{_('Read')}}</label>
</form>
</div>
</p>
{% endif %}
{% if entry.comments|length > 0 and entry.comments[0].text|length > 0%}
@@ -126,7 +136,7 @@
</button>
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
{% for format in entry.data %}
<li><a href="{{ url_for('get_download_link', book_id=entry.id, format=format.format|lower) }}">{{format.format}}</a></li>
<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>
{%endfor%}
</ul>
</div>
@@ -208,3 +218,34 @@
</div>
{% endblock %}
{% block js %}
<script src="{{ url_for('static', filename='js/libs/jquery.form.js') }}"></script>
<script>
$( document ).ready(function() {
var haveReadForm = $('#have_read_form');
haveReadForm.ajaxForm();
});
$("#have_read_container").attr('unselectable','on')
.css({'-moz-user-select':'-moz-none',
'-moz-user-select':'none',
'-o-user-select':'none',
'-khtml-user-select':'none', /* you could also put this in a class */
'-webkit-user-select':'none',/* and add the CSS class here instead */
'-ms-user-select':'none',
'user-select':'none'
}).bind('selectstart', function(){ return false; });
$("#have_read_container").click(function() {
var haveReadForm = $('#have_read_form');
if ($("#have_read").find('span').hasClass('glyphicon-ok')) {
$("#have_read").find('span').removeClass('glyphicon-ok');
$("#have_read").find('span').addClass('glyphicon-remove');
} else {
$("#have_read").find('span').removeClass('glyphicon-remove');
$("#have_read").find('span').addClass('glyphicon-ok');
}
haveReadForm.submit()
});
</script>
{% endblock %}

View File

@@ -35,6 +35,7 @@
<uri>https://github.com/janeczku/calibre-web</uri>
</author>
{% if entries and entries[0] %}
{% for entry in entries %}
<entry>
<title>{{entry.title}}</title>
@@ -60,6 +61,7 @@
{% endfor %}
</entry>
{% endfor %}
{% endif %}
{% for entry in listelements %}
<entry>
<title>{{entry.name}}</title>

View File

@@ -40,6 +40,7 @@
<div class="discover load-more">
<h2>{{title}}</h2>
<div class="row">
{% if entries[0] %}
{% for entry in entries %}
<div id="books" class="col-sm-3 col-lg-2 col-xs-6 book">
<div class="cover">
@@ -76,6 +77,7 @@
</div>
</div>
{% endfor %}
{% endif %}
</div>
</div>
{% endblock %}

View File

@@ -39,6 +39,20 @@
<id>{{url_for('feed_discover')}}</id>
<content type="text">{{_('Show Random Books')}}</content>
</entry>
<entry>
<title>{{_('Read Books')}}</title>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_read_books')}}" />
<link rel="subsection" href="{{url_for('feed_read_books')}}" type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition"/>
<id>{{url_for('feed_read_books')}}</id>
<content type="text">{{_('Read Books')}}</content>
</entry>
<entry>
<title>{{_('Unread Books')}}</title>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_unread_books')}}" />
<link rel="subsection" href="{{url_for('feed_unread_books')}}" type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition"/>
<id>{{url_for('feed_unread_books')}}</id>
<content type="text">{{_('Unread Books')}}</content>
</entry>
<entry>
<title>{{_('Authors')}}</title>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_authorindex')}}"/>

View File

@@ -128,6 +128,10 @@
{% if g.user.show_best_rated_books() %}
<li><a href="{{url_for('best_rated_books')}}"><span class="glyphicon glyphicon-star"></span> {{_('Best rated Books')}}</a></li>
{%endif%}
{% if g.user.show_read_and_unread() %}
<li><a href="{{url_for('read_books')}}"><span class="glyphicon glyphicon-eye-open"></span> {{_('Read Books')}}</a></li>
<li><a href="{{url_for('unread_books')}}"><span class="glyphicon glyphicon-eye-close"></span> {{_('Unread Books')}}</a></li>
{%endif%}
{% if g.user.show_random_books() %}
<li id="nav_rand"><a href="{{url_for('discover')}}"><span class="glyphicon glyphicon-random"></span> {{_('Discover')}}</a></li>
{%endif%}

View File

@@ -3,10 +3,11 @@
<div class="discover">
<h2>{{title}}</h2>
{% if g.user.is_authenticated %}
<a href="{{ url_for('delete_shelf', shelf_id=shelf.id) }}" class="btn btn-danger">{{ _('Delete this Shelf') }} </a>
<a href="{{ url_for('edit_shelf', shelf_id=shelf.id) }}" class="btn btn-primary">{{ _('Edit Shelf name') }} </a>
<a href="{{ url_for('order_shelf', shelf_id=shelf.id) }}" class="btn btn-primary">{{ _('Change order') }} </a>
{% if (g.user.role_edit_shelfs() and shelf.is_public ) or not shelf.is_public %}
<div data-toggle="modal" data-target="#DeleteShelfDialog" class="btn btn-danger">{{ _('Delete this Shelf') }} </div>
<a href="{{ url_for('edit_shelf', shelf_id=shelf.id) }}" class="btn btn-primary">{{ _('Edit Shelf name') }} </a>
<a href="{{ url_for('order_shelf', shelf_id=shelf.id) }}" class="btn btn-primary">{{ _('Change order') }} </a>
{% endif %}
{% endif %}
<div class="row">
@@ -39,4 +40,20 @@
{% endfor %}
</div>
</div>
<div id="DeleteShelfDialog" class="modal fade" role="dialog">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header bg-danger text-center">
<span>{{_('Do you really want to delete the shelf?')}}</span>
</div>
<div class="modal-body text-center">
<span>{{_('Shelf will be lost for everybody and forever!')}}</span>
<p></p>
<a href="{{ url_for('delete_shelf', shelf_id=shelf.id) }}" class="btn btn-danger">{{_('Ok')}}</a>
<button type="button" class="btn btn-default" data-dismiss="modal">{{_('Back')}}</button>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -7,11 +7,13 @@
<label for="title">{{_('Title')}}</label>
<input type="text" class="form-control" name="title" id="title" value="{{ shelf.name if shelf.name != None }}">
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="is_public" {% if shelf.is_public == 1 %}checked{% endif %}> {{_('should the shelf be public?')}}
</label>
</div>
{% if g.user.role_edit_shelfs() %}
<div class="checkbox">
<label>
<input type="checkbox" name="is_public" {% if shelf.is_public == 1 %}checked{% endif %}> {{_('should the shelf be public?')}}
</label>
</div>
{% endif %}
<button type="submit" class="btn btn-default">{{_('Submit')}}</button>
{% if shelf.id != None %}
<a href="{{ url_for('show_shelf', shelf_id=shelf.id) }}" class="btn btn-default">{{_('Back')}}</a>

View File

@@ -70,6 +70,10 @@
<input type="checkbox" name="show_author" id="show_author" {% if content.show_author() %}checked{% endif %}>
<label for="show_author">{{_('Show author selection')}}</label>
</div>
<div class="form-group">
<input type="checkbox" name="show_read_and_unread" id="show_read_and_unread" {% if content.show_read_and_unread() %}checked{% endif %}>
<label for="show_read_and_unread">{{_('Show read and unread')}}</label>
</div>
<div class="form-group">
<input type="checkbox" name="show_detail_random" id="show_detail_random" {% if content.show_detail_random() %}checked{% endif %}>
<label for="show_detail_random">{{_('Show random books in detail view')}}</label>
@@ -100,6 +104,10 @@
<input type="checkbox" name="passwd_role" id="passwd_role" {% if content.role_passwd() %}checked{% endif %}>
<label for="passwd_role">{{_('Allow Changing Password')}}</label>
</div>
<div class="form-group">
<input type="checkbox" name="edit_shelf_role" id="edit_shelf_role" {% if content.role_edit_shelfs() %}checked{% endif %}>
<label for="passwd_role">{{_('Allow Editing Public Shelfs')}}</label>
</div>
{% endif %}
{% endif %}
{% if g.user and g.user.role_admin() and not profile and not new_user and not content.role_anonymous() %}

View File

@@ -21,7 +21,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Calibre-web\n"
"Report-Msgid-Bugs-To: https://github.com/janeczku/calibre-web\n"
"POT-Creation-Date: 2017-02-20 19:47+0100\n"
"POT-Creation-Date: 2017-03-19 19:20+0100\n"
"PO-Revision-Date: 2016-07-12 19:54+0200\n"
"Last-Translator: Ozzie Isaacs\n"
"Language: de\n"
@@ -32,347 +32,360 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.3.4\n"
#: cps/book_formats.py:111 cps/book_formats.py:115 cps/web.py:1030
#: cps/book_formats.py:113 cps/book_formats.py:117 cps/web.py:1244
msgid "not installed"
msgstr "Nicht installiert"
#: cps/helper.py:150
#: cps/helper.py:164
#, python-format
msgid "Failed to send mail: %s"
msgstr "E-Mail: %s konnte nicht gesendet werden"
#: cps/helper.py:157
#: cps/helper.py:171
msgid "Calibre-web test email"
msgstr "Calibre-web Test E-Mail"
#: cps/helper.py:158 cps/helper.py:168
#: cps/helper.py:172 cps/helper.py:184
msgid "This email has been sent via calibre web."
msgstr "Die E-Mail wurde via calibre-web versendet"
#: cps/helper.py:167 cps/templates/detail.html:130
#: cps/helper.py:181 cps/templates/detail.html:146
msgid "Send to Kindle"
msgstr "An Kindle senden"
#: cps/helper.py:185 cps/helper.py:200
#: cps/helper.py:201 cps/helper.py:216
msgid "Could not find any formats suitable for sending by email"
msgstr ""
"Konnte keine Formate finden welche für das versenden per E-Mail geeignet "
"sind"
#: cps/helper.py:194
#: cps/helper.py:210
msgid "Could not convert epub to mobi"
msgstr "Konnte .epub nicht nach .mobi konvertieren"
#: cps/ub.py:434
#: cps/ub.py:488
msgid "Guest"
msgstr "Gast"
#: cps/web.py:734
#: cps/web.py:904
msgid "Requesting update package"
msgstr "Frage Update Paket an"
#: cps/web.py:735
#: cps/web.py:905
msgid "Downloading update package"
msgstr "Lade Update Paket herunter"
#: cps/web.py:736
#: cps/web.py:906
msgid "Unzipping update package"
msgstr "Entpacke Update Paket"
#: cps/web.py:737
#: cps/web.py:907
msgid "Files are replaced"
msgstr "Ersetze Dateien"
#: cps/web.py:738
#: cps/web.py:908
msgid "Database connections are closed"
msgstr "Schließe Datenbankverbindungen"
#: cps/web.py:739
#: cps/web.py:909
msgid "Server is stopped"
msgstr "Stoppe Server"
#: cps/web.py:740
#: cps/web.py:910
msgid "Update finished, please press okay and reload page"
msgstr "Update abgeschlossen, bitte okay drücken und Seite neu laden"
#: cps/web.py:810
#: cps/web.py:983
msgid "Latest Books"
msgstr "Letzte Bücher"
#: cps/web.py:835
#: cps/web.py:1014
msgid "Hot Books (most downloaded)"
msgstr "Beliebte Bücher (die meisten Downloads)"
#: cps/web.py:845
#: cps/web.py:1024
msgid "Best rated books"
msgstr "Best bewertete Bücher"
#: cps/templates/index.xml:36 cps/web.py:854
#: cps/templates/index.xml:36 cps/web.py:1033
msgid "Random Books"
msgstr "Zufällige Bücher"
#: cps/web.py:867
#: cps/web.py:1046
msgid "Author list"
msgstr "Autorenliste"
#: cps/web.py:878
#: cps/web.py:1057
#, python-format
msgid "Author: %(name)s"
msgstr "Autor: %(name)s"
#: cps/web.py:880 cps/web.py:908 cps/web.py:1007 cps/web.py:1235
#: cps/web.py:2115
#: cps/web.py:1059 cps/web.py:1087 cps/web.py:1221 cps/web.py:1626
#: cps/web.py:2579
msgid "Error opening eBook. File does not exist or file is not accessible:"
msgstr ""
"Buch öffnen fehlgeschlagen. Datei existiert nicht, oder ist nicht "
"zugänglich."
#: cps/templates/index.xml:57 cps/web.py:894
#: cps/templates/index.xml:71 cps/web.py:1073
msgid "Series list"
msgstr "Liste Serien"
#: cps/web.py:906
#: cps/web.py:1085
#, python-format
msgid "Series: %(serie)s"
msgstr "Serie: %(serie)s"
#: cps/web.py:939
#: cps/web.py:1118
msgid "Available languages"
msgstr "Verfügbare Sprachen"
#: cps/web.py:954
#: cps/web.py:1133
#, python-format
msgid "Language: %(name)s"
msgstr "Sprache: %(name)s"
#: cps/templates/index.xml:50 cps/web.py:967
#: cps/templates/index.xml:64 cps/web.py:1146
msgid "Category list"
msgstr "Kategorieliste"
#: cps/web.py:979
#: cps/web.py:1158
#, python-format
msgid "Category: %(name)s"
msgstr "Kategorie: %(name)s"
#: cps/web.py:1040
#: cps/web.py:1267
msgid "Statistics"
msgstr "Statistiken"
#: cps/web.py:1061
#: cps/web.py:1375
msgid "Server restarted, please reload page"
msgstr "Server neu gestartet,bitte Seite neu laden"
#: cps/web.py:1063
#: cps/web.py:1377
msgid "Performing shutdown of server, please close window"
msgstr "Server wird runtergefahren, bitte Fenster schließen"
#: cps/web.py:1073
#: cps/web.py:1392
msgid "Update done"
msgstr "Update durchgeführt"
#: cps/web.py:1147 cps/web.py:1160
#: cps/web.py:1470 cps/web.py:1483
msgid "search"
msgstr "Suche"
#: cps/web.py:1211 cps/web.py:1218 cps/web.py:1225 cps/web.py:1232
#: cps/web.py:1602 cps/web.py:1609 cps/web.py:1616 cps/web.py:1623
msgid "Read a Book"
msgstr "Lese ein Buch"
#: cps/web.py:1276 cps/web.py:1713
#: cps/web.py:1676 cps/web.py:2152
msgid "Please fill out all fields!"
msgstr "Bitte alle Felder ausfüllen!"
#: cps/web.py:1277 cps/web.py:1293 cps/web.py:1298 cps/web.py:1300
#: cps/web.py:1677 cps/web.py:1693 cps/web.py:1698 cps/web.py:1700
msgid "register"
msgstr "Registieren"
#: cps/web.py:1292
#: cps/web.py:1692
msgid "An unknown error occured. Please try again later."
msgstr "Es ist ein unbekannter Fehler aufgetreten. Bitte später erneut versuchen."
#: cps/web.py:1297
#: cps/web.py:1697
msgid "This username or email address is already in use."
msgstr "Der Benutzername oder die E-Mailadresse ist in bereits in Benutzung."
#: cps/web.py:1315
#: cps/web.py:1715
#, python-format
msgid "you are now logged in as: '%(nickname)s'"
msgstr "Du bist nun eingeloggt als '%(nickname)s'"
#: cps/web.py:1320
#: cps/web.py:1720
msgid "Wrong Username or Password"
msgstr "Falscher Benutzername oder Passwort"
#: cps/web.py:1322
#: cps/web.py:1722
msgid "login"
msgstr "Login"
#: cps/web.py:1339
#: cps/web.py:1739
msgid "Please configure the SMTP mail settings first..."
msgstr "Bitte zuerst die SMTP Mail Einstellung konfigurieren ..."
#: cps/web.py:1343
#: cps/web.py:1743
#, python-format
msgid "Book successfully send to %(kindlemail)s"
msgstr "Buch erfolgreich versandt an %(kindlemail)s"
#: cps/web.py:1347
#: cps/web.py:1747
#, python-format
msgid "There was an error sending this book: %(res)s"
msgstr "Beim Senden des Buchs trat ein Fehler auf: %(res)s"
#: cps/web.py:1349
#: cps/web.py:1749 cps/web.py:2232
msgid "Please configure your kindle email address first..."
msgstr "Bitte die Kindle E-Mail Adresse zuuerst konfigurieren..."
#: cps/web.py:1369
#: cps/web.py:1774
#, python-format
msgid "Book has been added to shelf: %(sname)s"
msgstr "Das Buch wurde dem Bücherregal: %(sname)s hinzugefügt"
#: cps/web.py:1390
#: cps/web.py:1793
#, python-format
msgid "Book has been removed from shelf: %(sname)s"
msgstr "Das Buch wurde aus dem Bücherregal: %(sname)s entfernt"
#: cps/web.py:1409 cps/web.py:1433
#: cps/web.py:1812 cps/web.py:1836
#, python-format
msgid "A shelf with the name '%(title)s' already exists."
msgstr "Es existiert bereits ein Bücheregal mit dem Titel '%(title)s'"
#: cps/web.py:1414
#: cps/web.py:1817
#, python-format
msgid "Shelf %(title)s created"
msgstr "Bücherregal %(title)s erzeugt"
#: cps/web.py:1416 cps/web.py:1444
#: cps/web.py:1819 cps/web.py:1847
msgid "There was an error"
msgstr "Es trat ein Fehler auf"
#: cps/web.py:1417 cps/web.py:1419
#: cps/web.py:1820 cps/web.py:1822
msgid "create a shelf"
msgstr "Bücherregal erzeugen"
#: cps/web.py:1442
#: cps/web.py:1845
#, python-format
msgid "Shelf %(title)s changed"
msgstr "Bücherregal %(title)s verändert"
#: cps/web.py:1445 cps/web.py:1447
#: cps/web.py:1848 cps/web.py:1850
msgid "Edit a shelf"
msgstr "Bücherregal editieren"
#: cps/web.py:1465
#: cps/web.py:1868
#, python-format
msgid "successfully deleted shelf %(name)s"
msgstr "Bücherregal %(name)s erfolgreich gelöscht"
#: cps/web.py:1487
#: cps/web.py:1890
#, python-format
msgid "Shelf: '%(name)s'"
msgstr "Bücherregal: '%(name)s'"
#: cps/web.py:1518
#: cps/web.py:1921
#, python-format
msgid "Change order of Shelf: '%(name)s'"
msgstr "Reihenfolge in Bücherregal '%(name)s' verändern"
#: cps/web.py:1580
#: cps/web.py:1985
msgid "Found an existing account for this email address."
msgstr "Es existiert ein Benutzerkonto für diese E-Mailadresse"
#: cps/web.py:1582 cps/web.py:1586
#: cps/web.py:1987 cps/web.py:1991
#, python-format
msgid "%(name)s's profile"
msgstr "%(name)s's Profil"
#: cps/web.py:1583
#: cps/web.py:1988
msgid "Profile updated"
msgstr "Profil aktualisiert"
#: cps/web.py:1597
#: cps/web.py:2002
msgid "Admin page"
msgstr "Admin Seite"
#: cps/web.py:1668
#: cps/web.py:2106
msgid "Calibre-web configuration updated"
msgstr "Calibre-web Konfiguration wurde aktualisiert"
#: cps/web.py:1675 cps/web.py:1681 cps/web.py:1694
#: cps/web.py:2113 cps/web.py:2119 cps/web.py:2133
msgid "Basic Configuration"
msgstr "Basis Konfiguration"
#: cps/web.py:1679
#: cps/web.py:2117
msgid "DB location is not valid, please enter correct path"
msgstr "DB Speicherort ist ungültig, bitte Pfad korrigieren"
#: cps/templates/admin.html:34 cps/web.py:1715 cps/web.py:1761
#: cps/templates/admin.html:34 cps/web.py:2154 cps/web.py:2202
msgid "Add new user"
msgstr "Neuen Benutzer hinzufügen"
#: cps/web.py:1753
#: cps/web.py:2194
#, python-format
msgid "User '%(user)s' created"
msgstr "Benutzer '%(user)s' angelegt"
#: cps/web.py:1757
#: cps/web.py:2198
msgid "Found an existing account for this email address or nickname."
msgstr ""
"Es existiert ein Benutzerkonto für diese Emailadresse oder den "
"Benutzernamen."
#: cps/web.py:1779
#: cps/web.py:2220
msgid "Mail settings updated"
msgstr "E-Mail Einstellungen aktualisiert"
#: cps/web.py:1785
#: cps/web.py:2227
#, python-format
msgid "Test E-Mail successfully send to %(kindlemail)s"
msgstr "Test E-Mail erfolgreich an %(kindlemail)s versendet"
#: cps/web.py:1788
#: cps/web.py:2230
#, python-format
msgid "There was an error sending the Test E-Mail: %(res)s"
msgstr "Fehler beim versenden der Test E-Mail: %(res)s"
#: cps/web.py:1789
#: cps/web.py:2234
msgid "E-Mail settings updated"
msgstr "E-Mail Einstellungen wurde aktualisiert"
#: cps/web.py:2235
msgid "Edit mail settings"
msgstr "E-Mail Einstellungen editieren"
#: cps/web.py:1817
#: cps/web.py:2263
#, python-format
msgid "User '%(nick)s' deleted"
msgstr "Benutzer '%(nick)s' gelöscht"
#: cps/web.py:1898
#: cps/web.py:2349
#, python-format
msgid "User '%(nick)s' updated"
msgstr "Benutzer '%(nick)s' aktualisiert"
#: cps/web.py:1901
#: cps/web.py:2352
msgid "An unknown error occured."
msgstr "Es ist ein unbekanter Fehler aufgetreten"
#: cps/web.py:1904
#: cps/web.py:2355
#, python-format
msgid "Edit User %(nick)s"
msgstr "Benutzer %(nick)s bearbeiten"
#: cps/web.py:2110 cps/web.py:2113 cps/web.py:2188
#: cps/web.py:2574 cps/web.py:2577 cps/web.py:2689
msgid "edit metadata"
msgstr "Metadaten editieren"
#: cps/web.py:2145
#: cps/web.py:2598
#, python-format
msgid "File extension \"%s\" is not allowed to be uploaded to this server"
msgstr "Die Dateiendung \"%s\" kann nicht auf diesen Server hochgeladen werden"
#: cps/web.py:2604
msgid "File to be uploaded must have an extension"
msgstr "Datei müssen eine Erweiterung haben, um hochgeladen zu werden"
#: cps/web.py:2621
#, python-format
msgid "Failed to create path %s (Permission denied)."
msgstr "Fehler beim Erzeugen des Pfads %s (Zugriff verweigert)"
#: cps/web.py:2150
#: cps/web.py:2626
#, python-format
msgid "Failed to store file %s (Permission denied)."
msgstr "Fehler beim speichern der Datei %s (Zugriff verweigert)"
#: cps/web.py:2155
#: cps/web.py:2631
#, python-format
msgid "Failed to delete file %s (Permission denied)."
msgstr "Fehler beim Löschen von Datei %s (Zugriff verweigert)"
@@ -401,7 +414,7 @@ msgstr "DLS"
msgid "Admin"
msgstr "Admin"
#: cps/templates/admin.html:13 cps/templates/detail.html:117
#: cps/templates/admin.html:13 cps/templates/detail.html:134
msgid "Download"
msgstr "Download"
@@ -457,7 +470,7 @@ msgstr "Konfiguration"
msgid "Calibre DB dir"
msgstr "Calibre DB Pfad"
#: cps/templates/admin.html:61 cps/templates/config_edit.html:32
#: cps/templates/admin.html:61 cps/templates/config_edit.html:76
msgid "Log Level"
msgstr "Log Level"
@@ -465,7 +478,7 @@ msgstr "Log Level"
msgid "Port"
msgstr "Port"
#: cps/templates/admin.html:63 cps/templates/config_edit.html:19
#: cps/templates/admin.html:63 cps/templates/config_edit.html:60
msgid "Books per page"
msgstr "Bücher pro Seite"
@@ -494,42 +507,46 @@ msgid "Newest commit timestamp"
msgstr "Neuestes Commit Datum"
#: cps/templates/admin.html:83
msgid "Reconnect to Calibre DB"
msgstr "Calibre-DB neu verbinden"
#: cps/templates/admin.html:84
msgid "Restart Calibre-web"
msgstr "Calibre-web Neustarten"
#: cps/templates/admin.html:84
#: cps/templates/admin.html:85
msgid "Stop Calibre-web"
msgstr "Stoppe Calibre-web"
#: cps/templates/admin.html:85
#: cps/templates/admin.html:86
msgid "Check for update"
msgstr "Suche nach Update"
#: cps/templates/admin.html:86
#: cps/templates/admin.html:87
msgid "Perform Update"
msgstr "Update durchführen"
#: cps/templates/admin.html:96
#: cps/templates/admin.html:97
msgid "Do you really want to restart Calibre-web?"
msgstr "Calibre-web wirklich neustarten?"
#: cps/templates/admin.html:101 cps/templates/admin.html:115
#: cps/templates/admin.html:136
#: cps/templates/admin.html:102 cps/templates/admin.html:116
#: cps/templates/admin.html:137
msgid "Ok"
msgstr "Ok"
#: cps/templates/admin.html:102 cps/templates/admin.html:116
#: cps/templates/book_edit.html:108 cps/templates/config_edit.html:75
#: cps/templates/admin.html:103 cps/templates/admin.html:117
#: cps/templates/book_edit.html:109 cps/templates/config_edit.html:119
#: cps/templates/email_edit.html:36 cps/templates/shelf_edit.html:17
#: cps/templates/shelf_order.html:12 cps/templates/user_edit.html:111
#: cps/templates/shelf_order.html:12 cps/templates/user_edit.html:120
msgid "Back"
msgstr "Zurück"
#: cps/templates/admin.html:114
#: cps/templates/admin.html:115
msgid "Do you really want to stop Calibre-web?"
msgstr "Calibre-web wirklich stoppen"
#: cps/templates/admin.html:127
#: cps/templates/admin.html:128
msgid "Updating, please do not reload page"
msgstr "Updatevorgang, bitte Seite nicht neu laden"
@@ -537,20 +554,21 @@ msgstr "Updatevorgang, bitte Seite nicht neu laden"
msgid "Book Title"
msgstr "Buchtitel"
#: cps/templates/book_edit.html:20 cps/templates/search_form.html:10
#: cps/templates/book_edit.html:20 cps/templates/book_edit.html:145
#: cps/templates/search_form.html:10
msgid "Author"
msgstr "Autor"
#: cps/templates/book_edit.html:24
#: cps/templates/book_edit.html:24 cps/templates/book_edit.html:147
msgid "Description"
msgstr "Beschreibung"
#: cps/templates/book_edit.html:28 cps/templates/search_form.html:13
#: cps/templates/book_edit.html:28 cps/templates/search_form.html:17
msgid "Tags"
msgstr "Tags"
#: cps/templates/book_edit.html:33 cps/templates/layout.html:138
#: cps/templates/search_form.html:33
#: cps/templates/book_edit.html:33 cps/templates/layout.html:142
#: cps/templates/search_form.html:37
msgid "Series"
msgstr "Serien"
@@ -582,69 +600,142 @@ msgstr "Nein"
msgid "view book after edit"
msgstr "Buch nach Bearbeitung ansehen"
#: cps/templates/book_edit.html:107 cps/templates/config_edit.html:73
#: cps/templates/login.html:19 cps/templates/search_form.html:75
#: cps/templates/shelf_edit.html:15 cps/templates/user_edit.html:109
#: cps/templates/book_edit.html:107 cps/templates/book_edit.html:118
msgid "Get metadata"
msgstr "Metadaten laden"
#: 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/shelf_edit.html:15 cps/templates/user_edit.html:118
msgid "Submit"
msgstr "Abschicken"
#: cps/templates/book_edit.html:121
msgid "Keyword"
msgstr "Suchbegriff"
#: cps/templates/book_edit.html:122
msgid " Search keyword "
msgstr "Suchbegriff"
#: cps/templates/book_edit.html:124 cps/templates/layout.html:60
msgid "Go!"
msgstr "Los!"
#: cps/templates/book_edit.html:125
msgid "Click the cover to load metadata to the form"
msgstr "Klicke auf das Bild um die Metadaten zu übertragen"
#: cps/templates/book_edit.html:129 cps/templates/book_edit.html:142
msgid "Loading..."
msgstr "Lade..."
#: cps/templates/book_edit.html:132
msgid "Close"
msgstr "Schließen"
#: cps/templates/book_edit.html:143
msgid "Search error!"
msgstr "Fehler bei Suche!"
#: cps/templates/book_edit.html:144
msgid "No Result! Please try anonther keyword."
msgstr "Kein Ergebniss! Bitte anderen Begriff versuchen"
#: cps/templates/book_edit.html:146 cps/templates/detail.html:76
#: cps/templates/search_form.html:14
msgid "Publisher"
msgstr "Herausgeber"
#: cps/templates/book_edit.html:148
msgid "Source"
msgstr "Quelle"
#: cps/templates/config_edit.html:7
msgid "Location of Calibre database"
msgstr "Speicherort der Calibre Datenbank"
#: cps/templates/config_edit.html:11
#: cps/templates/config_edit.html:13
msgid "Use google drive?"
msgstr "Google Drive benutzen"
#: cps/templates/config_edit.html:17
msgid "Client id"
msgstr "Benutzer Id"
#: cps/templates/config_edit.html:21
msgid "Client secret"
msgstr "Benutzer Secret"
#: cps/templates/config_edit.html:25
msgid "Calibre Base URL"
msgstr "Calibnre Basis URL"
#: cps/templates/config_edit.html:29
msgid "Google drive Calibre folder"
msgstr "Google Drive Calibre Ordner"
#: cps/templates/config_edit.html:38
msgid "Metadata Watch Channel ID"
msgstr "Matadata Überwachungs-ID"
#: cps/templates/config_edit.html:52
msgid "Server Port"
msgstr "Server Port"
#: cps/templates/config_edit.html:15 cps/templates/shelf_edit.html:7
#: cps/templates/config_edit.html:56 cps/templates/shelf_edit.html:7
msgid "Title"
msgstr "Titel"
#: cps/templates/config_edit.html:23
#: cps/templates/config_edit.html:64
msgid "No. of random books to show"
msgstr "Anzahl Anzeige zufällige Bücher"
#: cps/templates/config_edit.html:28
#: cps/templates/config_edit.html:68
msgid "Regular expression for ignoring columns"
msgstr "Regulärer Ausdruck um Spalten zu ignorien"
#: cps/templates/config_edit.html:72
msgid "Regular expression for title sorting"
msgstr "Regulärer Ausdruck für Titelsortierung"
#: cps/templates/config_edit.html:42
#: cps/templates/config_edit.html:86
msgid "Enable uploading"
msgstr "Hochladen aktivieren"
#: cps/templates/config_edit.html:46
#: cps/templates/config_edit.html:90
msgid "Enable anonymous browsing"
msgstr "Anonymes Browsen aktivieren"
#: cps/templates/config_edit.html:50
#: cps/templates/config_edit.html:94
msgid "Enable public registration"
msgstr "Öffentliche Registrierung aktivieren"
#: cps/templates/config_edit.html:52
#: cps/templates/config_edit.html:96
msgid "Default Settings for new users"
msgstr "Default Einstellungen für neue Benutzer"
#: cps/templates/config_edit.html:55 cps/templates/user_edit.html:80
#: cps/templates/config_edit.html:99 cps/templates/user_edit.html:87
msgid "Admin user"
msgstr "Admin Benutzer"
#: cps/templates/config_edit.html:59 cps/templates/user_edit.html:85
#: cps/templates/config_edit.html:103 cps/templates/user_edit.html:92
msgid "Allow Downloads"
msgstr "Downloads erlauben"
#: cps/templates/config_edit.html:63 cps/templates/user_edit.html:89
#: cps/templates/config_edit.html:107 cps/templates/user_edit.html:96
msgid "Allow Uploads"
msgstr "Uploads erlauben"
#: cps/templates/config_edit.html:67 cps/templates/user_edit.html:93
#: cps/templates/config_edit.html:111 cps/templates/user_edit.html:100
msgid "Allow Edit"
msgstr "Bearbeiten erlauben"
#: cps/templates/config_edit.html:71 cps/templates/user_edit.html:98
#: cps/templates/config_edit.html:115 cps/templates/user_edit.html:105
msgid "Allow Changing Password"
msgstr "Passwort ändern erlauben"
#: cps/templates/config_edit.html:78 cps/templates/layout.html:93
#: cps/templates/config_edit.html:122 cps/templates/layout.html:93
#: cps/templates/login.html:4
msgid "Login"
msgstr "Login"
@@ -661,23 +752,27 @@ msgstr "von"
msgid "language"
msgstr "Sprache"
#: cps/templates/detail.html:74
#: cps/templates/detail.html:81
msgid "Publishing date"
msgstr "Herausgabedatum"
#: cps/templates/detail.html:106
#: cps/templates/detail.html:115
msgid "Read"
msgstr "Gelesen"
#: cps/templates/detail.html:123
msgid "Description:"
msgstr "Beschreibung"
#: cps/templates/detail.html:134
#: cps/templates/detail.html:151
msgid "Read in browser"
msgstr "Im Browser lesen"
#: cps/templates/detail.html:154
#: cps/templates/detail.html:171
msgid "Add to shelf"
msgstr "Zu Bücherregal hinzufügen"
#: cps/templates/detail.html:194
#: cps/templates/detail.html:211
msgid "Edit metadata"
msgstr "Metadaten bearbeiten"
@@ -759,19 +854,29 @@ msgstr "Die neuesten Bücher"
msgid "Show Random Books"
msgstr "Zeige zufällige Bücher"
#: cps/templates/index.xml:43 cps/templates/layout.html:140
#: cps/templates/index.xml:43 cps/templates/index.xml:47
#: cps/templates/layout.html:132
msgid "Read Books"
msgstr "Gelesene Bücher"
#: cps/templates/index.xml:50 cps/templates/index.xml:54
#: cps/templates/layout.html:133
msgid "Unread Books"
msgstr "Ungelesene Bücher"
#: cps/templates/index.xml:57 cps/templates/layout.html:144
msgid "Authors"
msgstr "Autoren"
#: cps/templates/index.xml:47
#: cps/templates/index.xml:61
msgid "Books ordered by Author"
msgstr "Bücher nach Autoren sortiert"
#: cps/templates/index.xml:54
#: cps/templates/index.xml:68
msgid "Books ordered by category"
msgstr "Bücher nach Kategorien sortiert"
#: cps/templates/index.xml:61
#: cps/templates/index.xml:75
msgid "Books ordered by series"
msgstr "Bücher nach Reihen geordnet"
@@ -779,10 +884,6 @@ msgstr "Bücher nach Reihen geordnet"
msgid "Toggle navigation"
msgstr "Nagivation umschalten"
#: cps/templates/layout.html:60
msgid "Go!"
msgstr "Los!"
#: cps/templates/layout.html:68
msgid "Advanced Search"
msgstr "Erweiterte Suche"
@@ -799,31 +900,31 @@ msgstr "Registrieren"
msgid "Browse"
msgstr "Browsen"
#: cps/templates/layout.html:132
#: cps/templates/layout.html:136
msgid "Discover"
msgstr "Entdecke"
#: cps/templates/layout.html:135
#: cps/templates/layout.html:139
msgid "Categories"
msgstr "Kategorien"
#: cps/templates/layout.html:142 cps/templates/search_form.html:54
#: cps/templates/layout.html:146 cps/templates/search_form.html:58
msgid "Languages"
msgstr "Sprachen"
#: cps/templates/layout.html:145
#: cps/templates/layout.html:149
msgid "Public Shelves"
msgstr "Öffentiche Bücherregale"
#: cps/templates/layout.html:149
#: cps/templates/layout.html:153
msgid "Your Shelves"
msgstr "Deine Bücherregale"
#: cps/templates/layout.html:154
#: cps/templates/layout.html:158
msgid "Create a Shelf"
msgstr "Bücherregal erzeugen"
#: cps/templates/layout.html:155
#: cps/templates/layout.html:159
msgid "About"
msgstr "Über"
@@ -889,15 +990,15 @@ msgstr "Versuche eine andere Suche"
msgid "Results for:"
msgstr "Ergebnisse für:"
#: cps/templates/search_form.html:23
#: cps/templates/search_form.html:27
msgid "Exclude Tags"
msgstr "Tags ausschließen"
#: cps/templates/search_form.html:43
#: cps/templates/search_form.html:47
msgid "Exclude Series"
msgstr "Serie ausschließen"
#: cps/templates/search_form.html:64
#: cps/templates/search_form.html:68
msgid "Exclude Languages"
msgstr "Sprache ausschließen"
@@ -922,37 +1023,37 @@ msgid "Drag 'n drop to rearrange order"
msgstr "Drag 'n drop um Reihenfolge zu ändern"
#: cps/templates/stats.html:3
msgid "Linked libraries"
msgstr "Dynamische Bibliotheken"
#: cps/templates/stats.html:8
msgid "Program library"
msgstr "Programm Bibliotheken"
#: cps/templates/stats.html:9
msgid "Installed Version"
msgstr "Installierte Version"
#: cps/templates/stats.html:32
msgid "Calibre library statistics"
msgstr "Calibre Bibliothek Statistiken"
#: cps/templates/stats.html:37
#: cps/templates/stats.html:8
msgid "Books in this Library"
msgstr "Bücher in dieser Bibliothek"
#: cps/templates/stats.html:41
#: cps/templates/stats.html:12
msgid "Authors in this Library"
msgstr "Autoren in dieser Bibliothek"
#: cps/templates/stats.html:45
#: cps/templates/stats.html:16
msgid "Categories in this Library"
msgstr "Kategorien in dieser Bibliothek"
#: cps/templates/stats.html:49
#: cps/templates/stats.html:20
msgid "Series in this Library"
msgstr "Serien in dieser Bibliothek"
#: cps/templates/stats.html:24
msgid "Linked libraries"
msgstr "Dynamische Bibliotheken"
#: cps/templates/stats.html:28
msgid "Program library"
msgstr "Programm Bibliotheken"
#: cps/templates/stats.html:29
msgid "Installed Version"
msgstr "Installierte Version"
#: cps/templates/user_edit.html:23
msgid "Kindle E-Mail"
msgstr "Kindle E-Mail"
@@ -965,43 +1066,47 @@ msgstr "Zeige nur Bücher mit dieser Sprache"
msgid "Show all"
msgstr "Zeige alle"
#: cps/templates/user_edit.html:45
#: cps/templates/user_edit.html:47
msgid "Show random books"
msgstr "Zeige Zufällige Bücher"
#: cps/templates/user_edit.html:49
#: cps/templates/user_edit.html:51
msgid "Show hot books"
msgstr "Zeige Auswahl Beliebte Bücher"
#: cps/templates/user_edit.html:53
#: cps/templates/user_edit.html:55
msgid "Show best rated books"
msgstr "Zeige am besten bewertete Bücher"
#: cps/templates/user_edit.html:57
#: cps/templates/user_edit.html:59
msgid "Show language selection"
msgstr "Zeige Sprachauswahl"
#: cps/templates/user_edit.html:61
#: cps/templates/user_edit.html:63
msgid "Show series selection"
msgstr "Zeige Serienauswahl"
#: cps/templates/user_edit.html:65
#: cps/templates/user_edit.html:67
msgid "Show category selection"
msgstr "Zeige Kategorienauswahl"
#: cps/templates/user_edit.html:69
#: cps/templates/user_edit.html:71
msgid "Show author selection"
msgstr "Zeige Autorenauswahl"
#: cps/templates/user_edit.html:73
#: cps/templates/user_edit.html:75
msgid "Show read and unread"
msgstr "Zeige Gelesen/Ungelesen Auswahl"
#: cps/templates/user_edit.html:79
msgid "Show random books in detail view"
msgstr "Zeige zufällige Bücher in der Detailansicht"
#: cps/templates/user_edit.html:105
#: cps/templates/user_edit.html:112
msgid "Delete this user"
msgstr "Benutzer löschen"
#: cps/templates/user_edit.html:116
#: cps/templates/user_edit.html:127
msgid "Recent Downloads"
msgstr "Letzte Downloads"

View File

@@ -14,7 +14,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Calibre-web\n"
"Report-Msgid-Bugs-To: https://github.com/janeczku/calibre-web\n"
"POT-Creation-Date: 2017-02-20 19:47+0100\n"
"POT-Creation-Date: 2017-03-19 19:20+0100\n"
"PO-Revision-Date: 2016-11-13 18:35+0100\n"
"Last-Translator: Juan F. Villa <juan.villa@paisdelconocimiento.org>\n"
"Language: es\n"
@@ -25,341 +25,354 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.3.4\n"
#: cps/book_formats.py:111 cps/book_formats.py:115 cps/web.py:1030
#: cps/book_formats.py:113 cps/book_formats.py:117 cps/web.py:1244
msgid "not installed"
msgstr "No instalado"
#: cps/helper.py:150
#: cps/helper.py:164
#, python-format
msgid "Failed to send mail: %s"
msgstr "Fallo al enviar el correo : %s"
#: cps/helper.py:157
#: cps/helper.py:171
msgid "Calibre-web test email"
msgstr "Prueba de Correo Calibre-web"
#: cps/helper.py:158 cps/helper.py:168
#: cps/helper.py:172 cps/helper.py:184
msgid "This email has been sent via calibre web."
msgstr "Este mensaje ha sido enviado via Calibre Web."
#: cps/helper.py:167 cps/templates/detail.html:130
#: cps/helper.py:181 cps/templates/detail.html:146
msgid "Send to Kindle"
msgstr "Enviar a Kindle"
#: cps/helper.py:185 cps/helper.py:200
#: cps/helper.py:201 cps/helper.py:216
msgid "Could not find any formats suitable for sending by email"
msgstr "Formato no compatible para enviar por correo electronico"
#: cps/helper.py:194
#: cps/helper.py:210
msgid "Could not convert epub to mobi"
msgstr "No fue posible convertir de epub a mobi"
#: cps/ub.py:434
#: cps/ub.py:488
msgid "Guest"
msgstr ""
#: cps/web.py:734
#: cps/web.py:904
msgid "Requesting update package"
msgstr ""
#: cps/web.py:735
#: cps/web.py:905
msgid "Downloading update package"
msgstr ""
#: cps/web.py:736
#: cps/web.py:906
msgid "Unzipping update package"
msgstr ""
#: cps/web.py:737
#: cps/web.py:907
msgid "Files are replaced"
msgstr ""
#: cps/web.py:738
#: cps/web.py:908
msgid "Database connections are closed"
msgstr ""
#: cps/web.py:739
#: cps/web.py:909
msgid "Server is stopped"
msgstr ""
#: cps/web.py:740
#: cps/web.py:910
msgid "Update finished, please press okay and reload page"
msgstr ""
#: cps/web.py:810
#: cps/web.py:983
msgid "Latest Books"
msgstr "Libros recientes"
#: cps/web.py:835
#: cps/web.py:1014
msgid "Hot Books (most downloaded)"
msgstr "Libros Populares (los mas descargados)"
#: cps/web.py:845
#: cps/web.py:1024
msgid "Best rated books"
msgstr ""
#: cps/templates/index.xml:36 cps/web.py:854
#: cps/templates/index.xml:36 cps/web.py:1033
msgid "Random Books"
msgstr "Libros al Azar"
#: cps/web.py:867
#: cps/web.py:1046
msgid "Author list"
msgstr "Lista de Autores"
#: cps/web.py:878
#: cps/web.py:1057
#, python-format
msgid "Author: %(name)s"
msgstr ""
#: cps/web.py:880 cps/web.py:908 cps/web.py:1007 cps/web.py:1235
#: cps/web.py:2115
#: cps/web.py:1059 cps/web.py:1087 cps/web.py:1221 cps/web.py:1626
#: cps/web.py:2579
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"
#: cps/templates/index.xml:57 cps/web.py:894
#: cps/templates/index.xml:71 cps/web.py:1073
msgid "Series list"
msgstr "lista de Series"
#: cps/web.py:906
#: cps/web.py:1085
#, python-format
msgid "Series: %(serie)s"
msgstr "Series : %(serie)s"
#: cps/web.py:939
#: cps/web.py:1118
msgid "Available languages"
msgstr "Lenguajes disponibles"
#: cps/web.py:954
#: cps/web.py:1133
#, python-format
msgid "Language: %(name)s"
msgstr "Lenguaje: %(name)s"
#: cps/templates/index.xml:50 cps/web.py:967
#: cps/templates/index.xml:64 cps/web.py:1146
msgid "Category list"
msgstr "Lista de Categorias"
#: cps/web.py:979
#: cps/web.py:1158
#, python-format
msgid "Category: %(name)s"
msgstr "Categoria : %(name)s"
#: cps/web.py:1040
#: cps/web.py:1267
msgid "Statistics"
msgstr "Estadisticas"
#: cps/web.py:1061
#: cps/web.py:1375
msgid "Server restarted, please reload page"
msgstr ""
#: cps/web.py:1063
#: cps/web.py:1377
msgid "Performing shutdown of server, please close window"
msgstr ""
#: cps/web.py:1073
#: cps/web.py:1392
msgid "Update done"
msgstr ""
#: cps/web.py:1147 cps/web.py:1160
#: cps/web.py:1470 cps/web.py:1483
msgid "search"
msgstr ""
#: cps/web.py:1211 cps/web.py:1218 cps/web.py:1225 cps/web.py:1232
#: cps/web.py:1602 cps/web.py:1609 cps/web.py:1616 cps/web.py:1623
msgid "Read a Book"
msgstr "Leer un Libro"
#: cps/web.py:1276 cps/web.py:1713
#: cps/web.py:1676 cps/web.py:2152
msgid "Please fill out all fields!"
msgstr "Por favor llenar todos los campos!"
#: cps/web.py:1277 cps/web.py:1293 cps/web.py:1298 cps/web.py:1300
#: cps/web.py:1677 cps/web.py:1693 cps/web.py:1698 cps/web.py:1700
msgid "register"
msgstr "Registrarse"
#: cps/web.py:1292
#: cps/web.py:1692
msgid "An unknown error occured. Please try again later."
msgstr "Ocurrio un error. Intentar de nuevo mas tarde."
#: cps/web.py:1297
#: cps/web.py:1697
msgid "This username or email address is already in use."
msgstr "Usuario o direccion de correo en uso."
#: cps/web.py:1315
#: cps/web.py:1715
#, python-format
msgid "you are now logged in as: '%(nickname)s'"
msgstr "Sesion iniciada como : '%(nickname)s'"
#: cps/web.py:1320
#: cps/web.py:1720
msgid "Wrong Username or Password"
msgstr "Usuario o contraseña invalido"
#: cps/web.py:1322
#: cps/web.py:1722
msgid "login"
msgstr "Iniciar Sesion"
#: cps/web.py:1339
#: cps/web.py:1739
msgid "Please configure the SMTP mail settings first..."
msgstr "Configurar primero los parametros SMTP por favor..."
#: cps/web.py:1343
#: cps/web.py:1743
#, python-format
msgid "Book successfully send to %(kindlemail)s"
msgstr "Envio de Libro a %(kindlemail)s correctamente"
#: cps/web.py:1347
#: cps/web.py:1747
#, python-format
msgid "There was an error sending this book: %(res)s"
msgstr "Ha sucedido un error en el envio del Libro: %(res)s"
#: cps/web.py:1349
#: cps/web.py:1749 cps/web.py:2232
msgid "Please configure your kindle email address first..."
msgstr "Configurar primero la dirección de correo Kindle por favor..."
#: cps/web.py:1369
#: cps/web.py:1774
#, python-format
msgid "Book has been added to shelf: %(sname)s"
msgstr "El libro fue agregado a el estante: %(sname)s"
#: cps/web.py:1390
#: cps/web.py:1793
#, python-format
msgid "Book has been removed from shelf: %(sname)s"
msgstr "El libro fue removido del estante: %(sname)s"
#: cps/web.py:1409 cps/web.py:1433
#: cps/web.py:1812 cps/web.py:1836
#, python-format
msgid "A shelf with the name '%(title)s' already exists."
msgstr "Une étagère de ce nom '%(title)s' existe déjà."
#: cps/web.py:1414
#: cps/web.py:1817
#, python-format
msgid "Shelf %(title)s created"
msgstr "Estante %(title)s creado"
#: cps/web.py:1416 cps/web.py:1444
#: cps/web.py:1819 cps/web.py:1847
msgid "There was an error"
msgstr "Hemos tenido un error"
#: cps/web.py:1417 cps/web.py:1419
#: cps/web.py:1820 cps/web.py:1822
msgid "create a shelf"
msgstr "Crear un Estante"
#: cps/web.py:1442
#: cps/web.py:1845
#, python-format
msgid "Shelf %(title)s changed"
msgstr ""
#: cps/web.py:1445 cps/web.py:1447
#: cps/web.py:1848 cps/web.py:1850
msgid "Edit a shelf"
msgstr ""
#: cps/web.py:1465
#: cps/web.py:1868
#, python-format
msgid "successfully deleted shelf %(name)s"
msgstr "Estante %(name)s fue borrado correctamente"
#: cps/web.py:1487
#: cps/web.py:1890
#, python-format
msgid "Shelf: '%(name)s'"
msgstr "Estante: '%(name)s'"
#: cps/web.py:1518
#: cps/web.py:1921
#, python-format
msgid "Change order of Shelf: '%(name)s'"
msgstr ""
#: cps/web.py:1580
#: cps/web.py:1985
msgid "Found an existing account for this email address."
msgstr "Existe una cuenta vinculada a esta cuenta de correo."
#: cps/web.py:1582 cps/web.py:1586
#: cps/web.py:1987 cps/web.py:1991
#, python-format
msgid "%(name)s's profile"
msgstr "Perfil de %(name)s"
#: cps/web.py:1583
#: cps/web.py:1988
msgid "Profile updated"
msgstr "Perfil actualizado"
#: cps/web.py:1597
#: cps/web.py:2002
msgid "Admin page"
msgstr ""
#: cps/web.py:1668
#: cps/web.py:2106
msgid "Calibre-web configuration updated"
msgstr ""
#: cps/web.py:1675 cps/web.py:1681 cps/web.py:1694
#: cps/web.py:2113 cps/web.py:2119 cps/web.py:2133
msgid "Basic Configuration"
msgstr ""
#: cps/web.py:1679
#: cps/web.py:2117
msgid "DB location is not valid, please enter correct path"
msgstr ""
#: cps/templates/admin.html:34 cps/web.py:1715 cps/web.py:1761
#: cps/templates/admin.html:34 cps/web.py:2154 cps/web.py:2202
msgid "Add new user"
msgstr "Agregar un nuevo usuario"
#: cps/web.py:1753
#: cps/web.py:2194
#, python-format
msgid "User '%(user)s' created"
msgstr "Usuario '%(user)s' creado"
#: cps/web.py:1757
#: cps/web.py:2198
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."
#: cps/web.py:1779
#: cps/web.py:2220
msgid "Mail settings updated"
msgstr "Parametros de correo actualizados"
#: cps/web.py:1785
#: cps/web.py:2227
#, python-format
msgid "Test E-Mail successfully send to %(kindlemail)s"
msgstr "Exito al realizar envio de prueba a %(kindlemail)s"
#: cps/web.py:1788
#: cps/web.py:2230
#, python-format
msgid "There was an error sending the Test E-Mail: %(res)s"
msgstr "Error al realizar envio de prueba a E-Mail: %(res)s"
#: cps/web.py:1789
#: cps/web.py:2234
msgid "E-Mail settings updated"
msgstr ""
#: cps/web.py:2235
msgid "Edit mail settings"
msgstr "Editar parametros de correo"
#: cps/web.py:1817
#: cps/web.py:2263
#, python-format
msgid "User '%(nick)s' deleted"
msgstr "Usuario '%(nick)s' borrado"
#: cps/web.py:1898
#: cps/web.py:2349
#, python-format
msgid "User '%(nick)s' updated"
msgstr "Usuario '%(nick)s' Actualizado"
#: cps/web.py:1901
#: cps/web.py:2352
msgid "An unknown error occured."
msgstr "Oups ! Error inesperado."
#: cps/web.py:1904
#: cps/web.py:2355
#, python-format
msgid "Edit User %(nick)s"
msgstr "Editar Usuario %(nick)s"
#: cps/web.py:2110 cps/web.py:2113 cps/web.py:2188
#: cps/web.py:2574 cps/web.py:2577 cps/web.py:2689
msgid "edit metadata"
msgstr ""
#: cps/web.py:2145
#: cps/web.py:2598
#, python-format
msgid "File extension \"%s\" is not allowed to be uploaded to this server"
msgstr ""
#: cps/web.py:2604
msgid "File to be uploaded must have an extension"
msgstr ""
#: cps/web.py:2621
#, python-format
msgid "Failed to create path %s (Permission denied)."
msgstr "Fallo al crear la ruta %s (permiso negado)"
#: cps/web.py:2150
#: cps/web.py:2626
#, python-format
msgid "Failed to store file %s (Permission denied)."
msgstr "Fallo al almacenar el archivo %s (permiso negado)"
#: cps/web.py:2155
#: cps/web.py:2631
#, python-format
msgid "Failed to delete file %s (Permission denied)."
msgstr "Fallo al borrar el archivo %s (permiso negado)"
@@ -388,7 +401,7 @@ msgstr "DLS"
msgid "Admin"
msgstr "Administracion"
#: cps/templates/admin.html:13 cps/templates/detail.html:117
#: cps/templates/admin.html:13 cps/templates/detail.html:134
msgid "Download"
msgstr "Descarga"
@@ -444,7 +457,7 @@ msgstr ""
msgid "Calibre DB dir"
msgstr ""
#: cps/templates/admin.html:61 cps/templates/config_edit.html:32
#: cps/templates/admin.html:61 cps/templates/config_edit.html:76
msgid "Log Level"
msgstr ""
@@ -452,7 +465,7 @@ msgstr ""
msgid "Port"
msgstr ""
#: cps/templates/admin.html:63 cps/templates/config_edit.html:19
#: cps/templates/admin.html:63 cps/templates/config_edit.html:60
msgid "Books per page"
msgstr ""
@@ -481,42 +494,46 @@ msgid "Newest commit timestamp"
msgstr ""
#: cps/templates/admin.html:83
msgid "Restart Calibre-web"
msgid "Reconnect to Calibre DB"
msgstr ""
#: cps/templates/admin.html:84
msgid "Stop Calibre-web"
msgid "Restart Calibre-web"
msgstr ""
#: cps/templates/admin.html:85
msgid "Check for update"
msgid "Stop Calibre-web"
msgstr ""
#: cps/templates/admin.html:86
msgid "Check for update"
msgstr ""
#: cps/templates/admin.html:87
msgid "Perform Update"
msgstr ""
#: cps/templates/admin.html:96
#: cps/templates/admin.html:97
msgid "Do you really want to restart Calibre-web?"
msgstr ""
#: cps/templates/admin.html:101 cps/templates/admin.html:115
#: cps/templates/admin.html:136
#: cps/templates/admin.html:102 cps/templates/admin.html:116
#: cps/templates/admin.html:137
msgid "Ok"
msgstr ""
#: cps/templates/admin.html:102 cps/templates/admin.html:116
#: cps/templates/book_edit.html:108 cps/templates/config_edit.html:75
#: cps/templates/admin.html:103 cps/templates/admin.html:117
#: cps/templates/book_edit.html:109 cps/templates/config_edit.html:119
#: cps/templates/email_edit.html:36 cps/templates/shelf_edit.html:17
#: cps/templates/shelf_order.html:12 cps/templates/user_edit.html:111
#: cps/templates/shelf_order.html:12 cps/templates/user_edit.html:120
msgid "Back"
msgstr "Regresar"
#: cps/templates/admin.html:114
#: cps/templates/admin.html:115
msgid "Do you really want to stop Calibre-web?"
msgstr ""
#: cps/templates/admin.html:127
#: cps/templates/admin.html:128
msgid "Updating, please do not reload page"
msgstr ""
@@ -524,20 +541,21 @@ msgstr ""
msgid "Book Title"
msgstr "Titulo del Libro"
#: cps/templates/book_edit.html:20 cps/templates/search_form.html:10
#: cps/templates/book_edit.html:20 cps/templates/book_edit.html:145
#: cps/templates/search_form.html:10
msgid "Author"
msgstr "Autor"
#: cps/templates/book_edit.html:24
#: cps/templates/book_edit.html:24 cps/templates/book_edit.html:147
msgid "Description"
msgstr "Descripcion"
#: cps/templates/book_edit.html:28 cps/templates/search_form.html:13
#: cps/templates/book_edit.html:28 cps/templates/search_form.html:17
msgid "Tags"
msgstr "Etiqueta"
#: cps/templates/book_edit.html:33 cps/templates/layout.html:138
#: cps/templates/search_form.html:33
#: cps/templates/book_edit.html:33 cps/templates/layout.html:142
#: cps/templates/search_form.html:37
msgid "Series"
msgstr "Series"
@@ -569,69 +587,142 @@ msgstr "No"
msgid "view book after edit"
msgstr "Ver libro tras la edicion"
#: cps/templates/book_edit.html:107 cps/templates/config_edit.html:73
#: cps/templates/login.html:19 cps/templates/search_form.html:75
#: cps/templates/shelf_edit.html:15 cps/templates/user_edit.html:109
#: cps/templates/book_edit.html:107 cps/templates/book_edit.html:118
msgid "Get metadata"
msgstr ""
#: 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/shelf_edit.html:15 cps/templates/user_edit.html:118
msgid "Submit"
msgstr "Enviar"
#: cps/templates/book_edit.html:121
msgid "Keyword"
msgstr ""
#: cps/templates/book_edit.html:122
msgid " Search keyword "
msgstr ""
#: cps/templates/book_edit.html:124 cps/templates/layout.html:60
msgid "Go!"
msgstr "Vamos!"
#: cps/templates/book_edit.html:125
msgid "Click the cover to load metadata to the form"
msgstr ""
#: cps/templates/book_edit.html:129 cps/templates/book_edit.html:142
msgid "Loading..."
msgstr ""
#: cps/templates/book_edit.html:132
msgid "Close"
msgstr ""
#: cps/templates/book_edit.html:143
msgid "Search error!"
msgstr ""
#: cps/templates/book_edit.html:144
msgid "No Result! Please try anonther keyword."
msgstr ""
#: cps/templates/book_edit.html:146 cps/templates/detail.html:76
#: cps/templates/search_form.html:14
msgid "Publisher"
msgstr ""
#: cps/templates/book_edit.html:148
msgid "Source"
msgstr ""
#: cps/templates/config_edit.html:7
msgid "Location of Calibre database"
msgstr ""
#: cps/templates/config_edit.html:11
msgid "Server Port"
#: cps/templates/config_edit.html:13
msgid "Use google drive?"
msgstr ""
#: cps/templates/config_edit.html:15 cps/templates/shelf_edit.html:7
msgid "Title"
msgstr "Titulo"
#: cps/templates/config_edit.html:23
msgid "No. of random books to show"
#: cps/templates/config_edit.html:17
msgid "Client id"
msgstr ""
#: cps/templates/config_edit.html:28
msgid "Regular expression for title sorting"
#: cps/templates/config_edit.html:21
msgid "Client secret"
msgstr ""
#: cps/templates/config_edit.html:42
msgid "Enable uploading"
#: cps/templates/config_edit.html:25
msgid "Calibre Base URL"
msgstr ""
#: cps/templates/config_edit.html:46
msgid "Enable anonymous browsing"
#: cps/templates/config_edit.html:29
msgid "Google drive Calibre folder"
msgstr ""
#: cps/templates/config_edit.html:50
msgid "Enable public registration"
#: cps/templates/config_edit.html:38
msgid "Metadata Watch Channel ID"
msgstr ""
#: cps/templates/config_edit.html:52
msgid "Server Port"
msgstr ""
#: cps/templates/config_edit.html:56 cps/templates/shelf_edit.html:7
msgid "Title"
msgstr "Titulo"
#: cps/templates/config_edit.html:64
msgid "No. of random books to show"
msgstr ""
#: cps/templates/config_edit.html:68
msgid "Regular expression for ignoring columns"
msgstr ""
#: cps/templates/config_edit.html:72
msgid "Regular expression for title sorting"
msgstr ""
#: cps/templates/config_edit.html:86
msgid "Enable uploading"
msgstr ""
#: cps/templates/config_edit.html:90
msgid "Enable anonymous browsing"
msgstr ""
#: cps/templates/config_edit.html:94
msgid "Enable public registration"
msgstr ""
#: cps/templates/config_edit.html:96
msgid "Default Settings for new users"
msgstr ""
#: cps/templates/config_edit.html:55 cps/templates/user_edit.html:80
#: cps/templates/config_edit.html:99 cps/templates/user_edit.html:87
msgid "Admin user"
msgstr "Usuario Administrador"
#: cps/templates/config_edit.html:59 cps/templates/user_edit.html:85
#: cps/templates/config_edit.html:103 cps/templates/user_edit.html:92
msgid "Allow Downloads"
msgstr "Permitir descargas"
#: cps/templates/config_edit.html:63 cps/templates/user_edit.html:89
#: cps/templates/config_edit.html:107 cps/templates/user_edit.html:96
msgid "Allow Uploads"
msgstr "Permitir subidas de archivos"
#: cps/templates/config_edit.html:67 cps/templates/user_edit.html:93
#: cps/templates/config_edit.html:111 cps/templates/user_edit.html:100
msgid "Allow Edit"
msgstr "Permitir editar"
#: cps/templates/config_edit.html:71 cps/templates/user_edit.html:98
#: cps/templates/config_edit.html:115 cps/templates/user_edit.html:105
msgid "Allow Changing Password"
msgstr "Permitir cambiar la clave"
#: cps/templates/config_edit.html:78 cps/templates/layout.html:93
#: cps/templates/config_edit.html:122 cps/templates/layout.html:93
#: cps/templates/login.html:4
msgid "Login"
msgstr "Inicio de Sesion"
@@ -648,23 +739,27 @@ msgstr "de"
msgid "language"
msgstr "Lenguaje"
#: cps/templates/detail.html:74
#: cps/templates/detail.html:81
msgid "Publishing date"
msgstr ""
#: cps/templates/detail.html:106
#: cps/templates/detail.html:115
msgid "Read"
msgstr ""
#: cps/templates/detail.html:123
msgid "Description:"
msgstr "Descripcion :"
#: cps/templates/detail.html:134
#: cps/templates/detail.html:151
msgid "Read in browser"
msgstr "Ver en el navegador"
#: cps/templates/detail.html:154
#: cps/templates/detail.html:171
msgid "Add to shelf"
msgstr "Agregar al estante"
#: cps/templates/detail.html:194
#: cps/templates/detail.html:211
msgid "Edit metadata"
msgstr "Editar la metadata"
@@ -744,19 +839,29 @@ msgstr "Libros Recientes"
msgid "Show Random Books"
msgstr "Mostrar libros al azar"
#: cps/templates/index.xml:43 cps/templates/layout.html:140
#: cps/templates/index.xml:43 cps/templates/index.xml:47
#: cps/templates/layout.html:132
msgid "Read Books"
msgstr ""
#: cps/templates/index.xml:50 cps/templates/index.xml:54
#: cps/templates/layout.html:133
msgid "Unread Books"
msgstr ""
#: cps/templates/index.xml:57 cps/templates/layout.html:144
msgid "Authors"
msgstr "Autores"
#: cps/templates/index.xml:47
#: cps/templates/index.xml:61
msgid "Books ordered by Author"
msgstr "Libros ordenados por Autor"
#: cps/templates/index.xml:54
#: cps/templates/index.xml:68
msgid "Books ordered by category"
msgstr "Libros ordenados por Categorias"
#: cps/templates/index.xml:61
#: cps/templates/index.xml:75
msgid "Books ordered by series"
msgstr "Libros ordenados por Series"
@@ -764,10 +869,6 @@ msgstr "Libros ordenados por Series"
msgid "Toggle navigation"
msgstr ""
#: cps/templates/layout.html:60
msgid "Go!"
msgstr "Vamos!"
#: cps/templates/layout.html:68
msgid "Advanced Search"
msgstr "Busqueda avanzada"
@@ -784,31 +885,31 @@ msgstr "Registro"
msgid "Browse"
msgstr "Explorar"
#: cps/templates/layout.html:132
#: cps/templates/layout.html:136
msgid "Discover"
msgstr "Descubrir"
#: cps/templates/layout.html:135
#: cps/templates/layout.html:139
msgid "Categories"
msgstr "Categoria"
#: cps/templates/layout.html:142 cps/templates/search_form.html:54
#: cps/templates/layout.html:146 cps/templates/search_form.html:58
msgid "Languages"
msgstr "Lenguaje"
#: cps/templates/layout.html:145
#: cps/templates/layout.html:149
msgid "Public Shelves"
msgstr "Estantes Publicos"
#: cps/templates/layout.html:149
#: cps/templates/layout.html:153
msgid "Your Shelves"
msgstr "Sus Estantes"
#: cps/templates/layout.html:154
#: cps/templates/layout.html:158
msgid "Create a Shelf"
msgstr "Crear un estante"
#: cps/templates/layout.html:155
#: cps/templates/layout.html:159
msgid "About"
msgstr "Acerca de"
@@ -874,15 +975,15 @@ msgstr "Intente una busqueda diferente"
msgid "Results for:"
msgstr "Resultados para:"
#: cps/templates/search_form.html:23
#: cps/templates/search_form.html:27
msgid "Exclude Tags"
msgstr "Excluir etiquetas"
#: cps/templates/search_form.html:43
#: cps/templates/search_form.html:47
msgid "Exclude Series"
msgstr ""
#: cps/templates/search_form.html:64
#: cps/templates/search_form.html:68
msgid "Exclude Languages"
msgstr ""
@@ -907,37 +1008,37 @@ msgid "Drag 'n drop to rearrange order"
msgstr ""
#: cps/templates/stats.html:3
msgid "Linked libraries"
msgstr "Librerias vinculadas"
#: cps/templates/stats.html:8
msgid "Program library"
msgstr "Librerias del programa"
#: cps/templates/stats.html:9
msgid "Installed Version"
msgstr "Version instalada"
#: cps/templates/stats.html:32
msgid "Calibre library statistics"
msgstr "Estadisticas de la Biblioteca"
#: cps/templates/stats.html:37
#: cps/templates/stats.html:8
msgid "Books in this Library"
msgstr "Libros en esta Biblioteca"
#: cps/templates/stats.html:41
#: cps/templates/stats.html:12
msgid "Authors in this Library"
msgstr "Autores en esta Biblioteca"
#: cps/templates/stats.html:45
#: cps/templates/stats.html:16
msgid "Categories in this Library"
msgstr ""
#: cps/templates/stats.html:49
#: cps/templates/stats.html:20
msgid "Series in this Library"
msgstr ""
#: cps/templates/stats.html:24
msgid "Linked libraries"
msgstr "Librerias vinculadas"
#: cps/templates/stats.html:28
msgid "Program library"
msgstr "Librerias del programa"
#: cps/templates/stats.html:29
msgid "Installed Version"
msgstr "Version instalada"
#: cps/templates/user_edit.html:23
msgid "Kindle E-Mail"
msgstr "Correo del Kindle"
@@ -950,43 +1051,47 @@ msgstr "Mostrar lenguaje de los libros"
msgid "Show all"
msgstr "Mostrar Todo"
#: cps/templates/user_edit.html:45
#: cps/templates/user_edit.html:47
msgid "Show random books"
msgstr "Mostrar libros al azar"
#: cps/templates/user_edit.html:49
#: cps/templates/user_edit.html:51
msgid "Show hot books"
msgstr "Mostrar libros populares"
#: cps/templates/user_edit.html:53
#: cps/templates/user_edit.html:55
msgid "Show best rated books"
msgstr ""
#: cps/templates/user_edit.html:57
#: cps/templates/user_edit.html:59
msgid "Show language selection"
msgstr "Mostrar lenguaje seleccionado"
#: cps/templates/user_edit.html:61
#: cps/templates/user_edit.html:63
msgid "Show series selection"
msgstr "Mostrar series seleccionadas"
#: cps/templates/user_edit.html:65
#: cps/templates/user_edit.html:67
msgid "Show category selection"
msgstr "Mostrar categorias elegidas"
#: cps/templates/user_edit.html:69
#: cps/templates/user_edit.html:71
msgid "Show author selection"
msgstr ""
#: cps/templates/user_edit.html:73
#: cps/templates/user_edit.html:75
msgid "Show read and unread"
msgstr ""
#: cps/templates/user_edit.html:79
msgid "Show random books in detail view"
msgstr ""
#: cps/templates/user_edit.html:105
#: cps/templates/user_edit.html:112
msgid "Delete this user"
msgstr "Borrar este usuario"
#: cps/templates/user_edit.html:116
#: cps/templates/user_edit.html:127
msgid "Recent Downloads"
msgstr "Descargas Recientes"

View File

@@ -20,7 +20,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Calibre-web\n"
"Report-Msgid-Bugs-To: https://github.com/janeczku/calibre-web\n"
"POT-Creation-Date: 2017-02-20 19:47+0100\n"
"POT-Creation-Date: 2017-03-19 19:20+0100\n"
"PO-Revision-Date: 2016-11-13 18:35+0100\n"
"Last-Translator: Nicolas Roudninski <nicoroud@gmail.com>\n"
"Language: fr\n"
@@ -31,343 +31,356 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.3.4\n"
#: cps/book_formats.py:111 cps/book_formats.py:115 cps/web.py:1030
#: cps/book_formats.py:113 cps/book_formats.py:117 cps/web.py:1244
msgid "not installed"
msgstr ""
#: cps/helper.py:150
#: cps/helper.py:164
#, python-format
msgid "Failed to send mail: %s"
msgstr "Impossible d'envoyer le courriel : %s"
#: cps/helper.py:157
#: cps/helper.py:171
msgid "Calibre-web test email"
msgstr ""
#: cps/helper.py:158 cps/helper.py:168
#: cps/helper.py:172 cps/helper.py:184
msgid "This email has been sent via calibre web."
msgstr "Ce message a été envoyé depuis calibre web."
#: cps/helper.py:167 cps/templates/detail.html:130
#: cps/helper.py:181 cps/templates/detail.html:146
msgid "Send to Kindle"
msgstr "Envoyer ver Kindle"
#: cps/helper.py:185 cps/helper.py:200
#: cps/helper.py:201 cps/helper.py:216
msgid "Could not find any formats suitable for sending by email"
msgstr "Impossible de trouver un format adapté à envoyer par courriel"
#: cps/helper.py:194
#: cps/helper.py:210
msgid "Could not convert epub to mobi"
msgstr "Impossible de convertir epub vers mobi"
#: cps/ub.py:434
#: cps/ub.py:488
msgid "Guest"
msgstr ""
#: cps/web.py:734
#: cps/web.py:904
msgid "Requesting update package"
msgstr ""
#: cps/web.py:735
#: cps/web.py:905
msgid "Downloading update package"
msgstr ""
#: cps/web.py:736
#: cps/web.py:906
msgid "Unzipping update package"
msgstr ""
#: cps/web.py:737
#: cps/web.py:907
msgid "Files are replaced"
msgstr ""
#: cps/web.py:738
#: cps/web.py:908
msgid "Database connections are closed"
msgstr ""
#: cps/web.py:739
#: cps/web.py:909
msgid "Server is stopped"
msgstr ""
#: cps/web.py:740
#: cps/web.py:910
msgid "Update finished, please press okay and reload page"
msgstr ""
#: cps/web.py:810
#: cps/web.py:983
msgid "Latest Books"
msgstr "Derniers livres"
#: cps/web.py:835
#: cps/web.py:1014
msgid "Hot Books (most downloaded)"
msgstr "Livres populaires (les plus téléchargés)"
#: cps/web.py:845
#: cps/web.py:1024
msgid "Best rated books"
msgstr ""
#: cps/templates/index.xml:36 cps/web.py:854
#: cps/templates/index.xml:36 cps/web.py:1033
msgid "Random Books"
msgstr "Livres au hasard"
#: cps/web.py:867
#: cps/web.py:1046
msgid "Author list"
msgstr "Liste des auteurs"
#: cps/web.py:878
#: cps/web.py:1057
#, python-format
msgid "Author: %(name)s"
msgstr ""
#: cps/web.py:880 cps/web.py:908 cps/web.py:1007 cps/web.py:1235
#: cps/web.py:2115
#: cps/web.py:1059 cps/web.py:1087 cps/web.py:1221 cps/web.py:1626
#: cps/web.py:2579
msgid "Error opening eBook. File does not exist or file is not accessible:"
msgstr ""
"Erreur d'ouverture du livre numérique. Le fichier n'existe pas ou n'est "
"pas accessible :"
#: cps/templates/index.xml:57 cps/web.py:894
#: cps/templates/index.xml:71 cps/web.py:1073
msgid "Series list"
msgstr "Liste des séries"
#: cps/web.py:906
#: cps/web.py:1085
#, python-format
msgid "Series: %(serie)s"
msgstr "Séries : %(serie)s"
#: cps/web.py:939
#: cps/web.py:1118
msgid "Available languages"
msgstr "Langues disponibles"
#: cps/web.py:954
#: cps/web.py:1133
#, python-format
msgid "Language: %(name)s"
msgstr "Langue : %(name)s"
#: cps/templates/index.xml:50 cps/web.py:967
#: cps/templates/index.xml:64 cps/web.py:1146
msgid "Category list"
msgstr "Liste des catégories"
#: cps/web.py:979
#: cps/web.py:1158
#, python-format
msgid "Category: %(name)s"
msgstr "Catégorie : %(name)s"
#: cps/web.py:1040
#: cps/web.py:1267
msgid "Statistics"
msgstr "Statistiques"
#: cps/web.py:1061
#: cps/web.py:1375
msgid "Server restarted, please reload page"
msgstr ""
#: cps/web.py:1063
#: cps/web.py:1377
msgid "Performing shutdown of server, please close window"
msgstr ""
#: cps/web.py:1073
#: cps/web.py:1392
msgid "Update done"
msgstr ""
#: cps/web.py:1147 cps/web.py:1160
#: cps/web.py:1470 cps/web.py:1483
msgid "search"
msgstr ""
#: cps/web.py:1211 cps/web.py:1218 cps/web.py:1225 cps/web.py:1232
#: cps/web.py:1602 cps/web.py:1609 cps/web.py:1616 cps/web.py:1623
msgid "Read a Book"
msgstr "Lire un livre"
#: cps/web.py:1276 cps/web.py:1713
#: cps/web.py:1676 cps/web.py:2152
msgid "Please fill out all fields!"
msgstr "SVP, complétez tous les champs !"
#: cps/web.py:1277 cps/web.py:1293 cps/web.py:1298 cps/web.py:1300
#: cps/web.py:1677 cps/web.py:1693 cps/web.py:1698 cps/web.py:1700
msgid "register"
msgstr "S'enregistrer"
#: cps/web.py:1292
#: cps/web.py:1692
msgid "An unknown error occured. Please try again later."
msgstr "Une erreur a eu lieu. Merci de réessayez plus tard."
#: cps/web.py:1297
#: cps/web.py:1697
msgid "This username or email address is already in use."
msgstr "Ce nom d'utilisateur ou cette adresse de courriel est déjà utilisée."
#: cps/web.py:1315
#: cps/web.py:1715
#, python-format
msgid "you are now logged in as: '%(nickname)s'"
msgstr "Vous êtes maintenant connecté sous : '%(nickname)s'"
#: cps/web.py:1320
#: cps/web.py:1720
msgid "Wrong Username or Password"
msgstr "Mauvais nom d'utilisateur ou mot de passe"
#: cps/web.py:1322
#: cps/web.py:1722
msgid "login"
msgstr "Connexion"
#: cps/web.py:1339
#: cps/web.py:1739
msgid "Please configure the SMTP mail settings first..."
msgstr "Veillez configurer les paramètres smtp d'abord..."
#: cps/web.py:1343
#: cps/web.py:1743
#, python-format
msgid "Book successfully send to %(kindlemail)s"
msgstr "Livres envoyés à %(kindlemail)s avec succès"
#: cps/web.py:1347
#: cps/web.py:1747
#, python-format
msgid "There was an error sending this book: %(res)s"
msgstr "Il y a eu une erreur en envoyant ce livre : %(res)s"
#: cps/web.py:1349
#: cps/web.py:1749 cps/web.py:2232
msgid "Please configure your kindle email address first..."
msgstr "Veuillez configurer votre adresse kindle d'abord..."
#: cps/web.py:1369
#: cps/web.py:1774
#, python-format
msgid "Book has been added to shelf: %(sname)s"
msgstr "Le livre a bien été ajouté à l'étagère : %(sname)s"
#: cps/web.py:1390
#: cps/web.py:1793
#, python-format
msgid "Book has been removed from shelf: %(sname)s"
msgstr "Le livre a été supprimé de l'étagère %(sname)s"
#: cps/web.py:1409 cps/web.py:1433
#: cps/web.py:1812 cps/web.py:1836
#, python-format
msgid "A shelf with the name '%(title)s' already exists."
msgstr "Une étagère de ce nom '%(title)s' existe déjà."
#: cps/web.py:1414
#: cps/web.py:1817
#, python-format
msgid "Shelf %(title)s created"
msgstr "Étagère %(title)s créée"
#: cps/web.py:1416 cps/web.py:1444
#: cps/web.py:1819 cps/web.py:1847
msgid "There was an error"
msgstr "Il y a eu une erreur"
#: cps/web.py:1417 cps/web.py:1419
#: cps/web.py:1820 cps/web.py:1822
msgid "create a shelf"
msgstr "Créer une étagère"
#: cps/web.py:1442
#: cps/web.py:1845
#, python-format
msgid "Shelf %(title)s changed"
msgstr ""
#: cps/web.py:1445 cps/web.py:1447
#: cps/web.py:1848 cps/web.py:1850
msgid "Edit a shelf"
msgstr ""
#: cps/web.py:1465
#: cps/web.py:1868
#, python-format
msgid "successfully deleted shelf %(name)s"
msgstr "L'étagère %(name)s a été supprimé avec succès"
#: cps/web.py:1487
#: cps/web.py:1890
#, python-format
msgid "Shelf: '%(name)s'"
msgstr "Étagère : '%(name)s'"
#: cps/web.py:1518
#: cps/web.py:1921
#, python-format
msgid "Change order of Shelf: '%(name)s'"
msgstr ""
#: cps/web.py:1580
#: cps/web.py:1985
msgid "Found an existing account for this email address."
msgstr "Un compte avec cette adresse de courriel existe déjà."
#: cps/web.py:1582 cps/web.py:1586
#: cps/web.py:1987 cps/web.py:1991
#, python-format
msgid "%(name)s's profile"
msgstr "Profil de %(name)s"
#: cps/web.py:1583
#: cps/web.py:1988
msgid "Profile updated"
msgstr "Profil mis à jour"
#: cps/web.py:1597
#: cps/web.py:2002
msgid "Admin page"
msgstr ""
#: cps/web.py:1668
#: cps/web.py:2106
msgid "Calibre-web configuration updated"
msgstr ""
#: cps/web.py:1675 cps/web.py:1681 cps/web.py:1694
#: cps/web.py:2113 cps/web.py:2119 cps/web.py:2133
msgid "Basic Configuration"
msgstr ""
#: cps/web.py:1679
#: cps/web.py:2117
msgid "DB location is not valid, please enter correct path"
msgstr ""
#: cps/templates/admin.html:34 cps/web.py:1715 cps/web.py:1761
#: cps/templates/admin.html:34 cps/web.py:2154 cps/web.py:2202
msgid "Add new user"
msgstr "Ajouter un nouvel utilisateur"
#: cps/web.py:1753
#: cps/web.py:2194
#, python-format
msgid "User '%(user)s' created"
msgstr "Utilisateur '%(user)s' créé"
#: cps/web.py:1757
#: cps/web.py:2198
msgid "Found an existing account for this email address or nickname."
msgstr "Un compte avec cette adresse de courriel ou ce surnom existe déjà."
#: cps/web.py:1779
#: cps/web.py:2220
msgid "Mail settings updated"
msgstr "Paramètres de courriel mis à jour"
#: cps/web.py:1785
#: cps/web.py:2227
#, python-format
msgid "Test E-Mail successfully send to %(kindlemail)s"
msgstr ""
#: cps/web.py:1788
#: cps/web.py:2230
#, python-format
msgid "There was an error sending the Test E-Mail: %(res)s"
msgstr ""
#: cps/web.py:1789
#: cps/web.py:2234
msgid "E-Mail settings updated"
msgstr ""
#: cps/web.py:2235
msgid "Edit mail settings"
msgstr "Éditer les paramètres de courriel"
#: cps/web.py:1817
#: cps/web.py:2263
#, python-format
msgid "User '%(nick)s' deleted"
msgstr "Utilisateur '%(nick)s' supprimé"
#: cps/web.py:1898
#: cps/web.py:2349
#, python-format
msgid "User '%(nick)s' updated"
msgstr "Utilisateur '%(nick)s' mis à jour"
#: cps/web.py:1901
#: cps/web.py:2352
msgid "An unknown error occured."
msgstr "Oups ! Une erreur inconnue a eu lieu."
#: cps/web.py:1904
#: cps/web.py:2355
#, python-format
msgid "Edit User %(nick)s"
msgstr "Éditer l'utilisateur %(nick)s"
#: cps/web.py:2110 cps/web.py:2113 cps/web.py:2188
#: cps/web.py:2574 cps/web.py:2577 cps/web.py:2689
msgid "edit metadata"
msgstr ""
#: cps/web.py:2145
#: cps/web.py:2598
#, python-format
msgid "File extension \"%s\" is not allowed to be uploaded to this server"
msgstr ""
#: cps/web.py:2604
msgid "File to be uploaded must have an extension"
msgstr ""
#: cps/web.py:2621
#, python-format
msgid "Failed to create path %s (Permission denied)."
msgstr "Impossible de créer le chemin %s (permission refusée)"
#: cps/web.py:2150
#: cps/web.py:2626
#, python-format
msgid "Failed to store file %s (Permission denied)."
msgstr "Impossible d'enregistrer le fichier %s (permission refusée)"
#: cps/web.py:2155
#: cps/web.py:2631
#, python-format
msgid "Failed to delete file %s (Permission denied)."
msgstr "Impossible de supprimer le fichier %s (permission refusée)"
@@ -396,7 +409,7 @@ msgstr "DLS"
msgid "Admin"
msgstr "Administration"
#: cps/templates/admin.html:13 cps/templates/detail.html:117
#: cps/templates/admin.html:13 cps/templates/detail.html:134
msgid "Download"
msgstr "Télécharger"
@@ -452,7 +465,7 @@ msgstr ""
msgid "Calibre DB dir"
msgstr ""
#: cps/templates/admin.html:61 cps/templates/config_edit.html:32
#: cps/templates/admin.html:61 cps/templates/config_edit.html:76
msgid "Log Level"
msgstr ""
@@ -460,7 +473,7 @@ msgstr ""
msgid "Port"
msgstr ""
#: cps/templates/admin.html:63 cps/templates/config_edit.html:19
#: cps/templates/admin.html:63 cps/templates/config_edit.html:60
msgid "Books per page"
msgstr ""
@@ -489,42 +502,46 @@ msgid "Newest commit timestamp"
msgstr ""
#: cps/templates/admin.html:83
msgid "Restart Calibre-web"
msgid "Reconnect to Calibre DB"
msgstr ""
#: cps/templates/admin.html:84
msgid "Stop Calibre-web"
msgid "Restart Calibre-web"
msgstr ""
#: cps/templates/admin.html:85
msgid "Check for update"
msgid "Stop Calibre-web"
msgstr ""
#: cps/templates/admin.html:86
msgid "Check for update"
msgstr ""
#: cps/templates/admin.html:87
msgid "Perform Update"
msgstr ""
#: cps/templates/admin.html:96
#: cps/templates/admin.html:97
msgid "Do you really want to restart Calibre-web?"
msgstr ""
#: cps/templates/admin.html:101 cps/templates/admin.html:115
#: cps/templates/admin.html:136
#: cps/templates/admin.html:102 cps/templates/admin.html:116
#: cps/templates/admin.html:137
msgid "Ok"
msgstr ""
#: cps/templates/admin.html:102 cps/templates/admin.html:116
#: cps/templates/book_edit.html:108 cps/templates/config_edit.html:75
#: cps/templates/admin.html:103 cps/templates/admin.html:117
#: cps/templates/book_edit.html:109 cps/templates/config_edit.html:119
#: cps/templates/email_edit.html:36 cps/templates/shelf_edit.html:17
#: cps/templates/shelf_order.html:12 cps/templates/user_edit.html:111
#: cps/templates/shelf_order.html:12 cps/templates/user_edit.html:120
msgid "Back"
msgstr "Retour"
#: cps/templates/admin.html:114
#: cps/templates/admin.html:115
msgid "Do you really want to stop Calibre-web?"
msgstr ""
#: cps/templates/admin.html:127
#: cps/templates/admin.html:128
msgid "Updating, please do not reload page"
msgstr ""
@@ -532,20 +549,21 @@ msgstr ""
msgid "Book Title"
msgstr "Titre du livre"
#: cps/templates/book_edit.html:20 cps/templates/search_form.html:10
#: cps/templates/book_edit.html:20 cps/templates/book_edit.html:145
#: cps/templates/search_form.html:10
msgid "Author"
msgstr "Auteur"
#: cps/templates/book_edit.html:24
#: cps/templates/book_edit.html:24 cps/templates/book_edit.html:147
msgid "Description"
msgstr "Description"
#: cps/templates/book_edit.html:28 cps/templates/search_form.html:13
#: cps/templates/book_edit.html:28 cps/templates/search_form.html:17
msgid "Tags"
msgstr "Étiquette"
#: cps/templates/book_edit.html:33 cps/templates/layout.html:138
#: cps/templates/search_form.html:33
#: cps/templates/book_edit.html:33 cps/templates/layout.html:142
#: cps/templates/search_form.html:37
msgid "Series"
msgstr "Séries"
@@ -577,69 +595,142 @@ msgstr "Non"
msgid "view book after edit"
msgstr "Voir le livre après l'édition"
#: cps/templates/book_edit.html:107 cps/templates/config_edit.html:73
#: cps/templates/login.html:19 cps/templates/search_form.html:75
#: cps/templates/shelf_edit.html:15 cps/templates/user_edit.html:109
#: cps/templates/book_edit.html:107 cps/templates/book_edit.html:118
msgid "Get metadata"
msgstr ""
#: 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/shelf_edit.html:15 cps/templates/user_edit.html:118
msgid "Submit"
msgstr "Soumettre"
#: cps/templates/book_edit.html:121
msgid "Keyword"
msgstr ""
#: cps/templates/book_edit.html:122
msgid " Search keyword "
msgstr ""
#: cps/templates/book_edit.html:124 cps/templates/layout.html:60
msgid "Go!"
msgstr "Allez !"
#: cps/templates/book_edit.html:125
msgid "Click the cover to load metadata to the form"
msgstr ""
#: cps/templates/book_edit.html:129 cps/templates/book_edit.html:142
msgid "Loading..."
msgstr ""
#: cps/templates/book_edit.html:132
msgid "Close"
msgstr ""
#: cps/templates/book_edit.html:143
msgid "Search error!"
msgstr ""
#: cps/templates/book_edit.html:144
msgid "No Result! Please try anonther keyword."
msgstr ""
#: cps/templates/book_edit.html:146 cps/templates/detail.html:76
#: cps/templates/search_form.html:14
msgid "Publisher"
msgstr ""
#: cps/templates/book_edit.html:148
msgid "Source"
msgstr ""
#: cps/templates/config_edit.html:7
msgid "Location of Calibre database"
msgstr ""
#: cps/templates/config_edit.html:11
msgid "Server Port"
#: cps/templates/config_edit.html:13
msgid "Use google drive?"
msgstr ""
#: cps/templates/config_edit.html:15 cps/templates/shelf_edit.html:7
msgid "Title"
msgstr "Titre"
#: cps/templates/config_edit.html:23
msgid "No. of random books to show"
#: cps/templates/config_edit.html:17
msgid "Client id"
msgstr ""
#: cps/templates/config_edit.html:28
msgid "Regular expression for title sorting"
#: cps/templates/config_edit.html:21
msgid "Client secret"
msgstr ""
#: cps/templates/config_edit.html:42
msgid "Enable uploading"
#: cps/templates/config_edit.html:25
msgid "Calibre Base URL"
msgstr ""
#: cps/templates/config_edit.html:46
msgid "Enable anonymous browsing"
#: cps/templates/config_edit.html:29
msgid "Google drive Calibre folder"
msgstr ""
#: cps/templates/config_edit.html:50
msgid "Enable public registration"
#: cps/templates/config_edit.html:38
msgid "Metadata Watch Channel ID"
msgstr ""
#: cps/templates/config_edit.html:52
msgid "Server Port"
msgstr ""
#: cps/templates/config_edit.html:56 cps/templates/shelf_edit.html:7
msgid "Title"
msgstr "Titre"
#: cps/templates/config_edit.html:64
msgid "No. of random books to show"
msgstr ""
#: cps/templates/config_edit.html:68
msgid "Regular expression for ignoring columns"
msgstr ""
#: cps/templates/config_edit.html:72
msgid "Regular expression for title sorting"
msgstr ""
#: cps/templates/config_edit.html:86
msgid "Enable uploading"
msgstr ""
#: cps/templates/config_edit.html:90
msgid "Enable anonymous browsing"
msgstr ""
#: cps/templates/config_edit.html:94
msgid "Enable public registration"
msgstr ""
#: cps/templates/config_edit.html:96
msgid "Default Settings for new users"
msgstr ""
#: cps/templates/config_edit.html:55 cps/templates/user_edit.html:80
#: cps/templates/config_edit.html:99 cps/templates/user_edit.html:87
msgid "Admin user"
msgstr "Utilisateur admin"
#: cps/templates/config_edit.html:59 cps/templates/user_edit.html:85
#: cps/templates/config_edit.html:103 cps/templates/user_edit.html:92
msgid "Allow Downloads"
msgstr "Permettre les téléchargements"
#: cps/templates/config_edit.html:63 cps/templates/user_edit.html:89
#: cps/templates/config_edit.html:107 cps/templates/user_edit.html:96
msgid "Allow Uploads"
msgstr "Permettre les téléversements"
#: cps/templates/config_edit.html:67 cps/templates/user_edit.html:93
#: cps/templates/config_edit.html:111 cps/templates/user_edit.html:100
msgid "Allow Edit"
msgstr "Permettre l'édition"
#: cps/templates/config_edit.html:71 cps/templates/user_edit.html:98
#: cps/templates/config_edit.html:115 cps/templates/user_edit.html:105
msgid "Allow Changing Password"
msgstr "Permettre le changement de mot de passe"
#: cps/templates/config_edit.html:78 cps/templates/layout.html:93
#: cps/templates/config_edit.html:122 cps/templates/layout.html:93
#: cps/templates/login.html:4
msgid "Login"
msgstr "Connexion"
@@ -656,23 +747,27 @@ msgstr ""
msgid "language"
msgstr "Langue"
#: cps/templates/detail.html:74
#: cps/templates/detail.html:81
msgid "Publishing date"
msgstr ""
#: cps/templates/detail.html:106
#: cps/templates/detail.html:115
msgid "Read"
msgstr ""
#: cps/templates/detail.html:123
msgid "Description:"
msgstr "Description :"
#: cps/templates/detail.html:134
#: cps/templates/detail.html:151
msgid "Read in browser"
msgstr "Lire dans le navigateur"
#: cps/templates/detail.html:154
#: cps/templates/detail.html:171
msgid "Add to shelf"
msgstr "Ajouter à l'étagère"
#: cps/templates/detail.html:194
#: cps/templates/detail.html:211
msgid "Edit metadata"
msgstr "Éditer les métadonnées"
@@ -752,19 +847,29 @@ msgstr "Les derniers livres"
msgid "Show Random Books"
msgstr "Montrer des livres au hasard"
#: cps/templates/index.xml:43 cps/templates/layout.html:140
#: cps/templates/index.xml:43 cps/templates/index.xml:47
#: cps/templates/layout.html:132
msgid "Read Books"
msgstr ""
#: cps/templates/index.xml:50 cps/templates/index.xml:54
#: cps/templates/layout.html:133
msgid "Unread Books"
msgstr ""
#: cps/templates/index.xml:57 cps/templates/layout.html:144
msgid "Authors"
msgstr "Auteurs"
#: cps/templates/index.xml:47
#: cps/templates/index.xml:61
msgid "Books ordered by Author"
msgstr "Livres classés par auteur"
#: cps/templates/index.xml:54
#: cps/templates/index.xml:68
msgid "Books ordered by category"
msgstr "Livres classés par catégorie"
#: cps/templates/index.xml:61
#: cps/templates/index.xml:75
msgid "Books ordered by series"
msgstr "Livres classés par série"
@@ -772,10 +877,6 @@ msgstr "Livres classés par série"
msgid "Toggle navigation"
msgstr "Basculer la navigation"
#: cps/templates/layout.html:60
msgid "Go!"
msgstr "Allez !"
#: cps/templates/layout.html:68
msgid "Advanced Search"
msgstr "Recherche avancée"
@@ -792,31 +893,31 @@ msgstr "S'enregistrer"
msgid "Browse"
msgstr "Explorer"
#: cps/templates/layout.html:132
#: cps/templates/layout.html:136
msgid "Discover"
msgstr "Découvrir"
#: cps/templates/layout.html:135
#: cps/templates/layout.html:139
msgid "Categories"
msgstr "Catégories"
#: cps/templates/layout.html:142 cps/templates/search_form.html:54
#: cps/templates/layout.html:146 cps/templates/search_form.html:58
msgid "Languages"
msgstr "Langues"
#: cps/templates/layout.html:145
#: cps/templates/layout.html:149
msgid "Public Shelves"
msgstr "Étagères publiques"
#: cps/templates/layout.html:149
#: cps/templates/layout.html:153
msgid "Your Shelves"
msgstr "Vos étagères"
#: cps/templates/layout.html:154
#: cps/templates/layout.html:158
msgid "Create a Shelf"
msgstr "Créer une étagère"
#: cps/templates/layout.html:155
#: cps/templates/layout.html:159
msgid "About"
msgstr "À popos"
@@ -882,15 +983,15 @@ msgstr "Essayer une recherche différente"
msgid "Results for:"
msgstr "Résultats pour :"
#: cps/templates/search_form.html:23
#: cps/templates/search_form.html:27
msgid "Exclude Tags"
msgstr "Exclure des étiquettes"
#: cps/templates/search_form.html:43
#: cps/templates/search_form.html:47
msgid "Exclude Series"
msgstr ""
#: cps/templates/search_form.html:64
#: cps/templates/search_form.html:68
msgid "Exclude Languages"
msgstr ""
@@ -915,37 +1016,37 @@ msgid "Drag 'n drop to rearrange order"
msgstr ""
#: cps/templates/stats.html:3
msgid "Linked libraries"
msgstr ""
#: cps/templates/stats.html:8
msgid "Program library"
msgstr ""
#: cps/templates/stats.html:9
msgid "Installed Version"
msgstr ""
#: cps/templates/stats.html:32
msgid "Calibre library statistics"
msgstr ""
#: cps/templates/stats.html:37
#: cps/templates/stats.html:8
msgid "Books in this Library"
msgstr "Livres dans la bibiothèque"
#: cps/templates/stats.html:41
#: cps/templates/stats.html:12
msgid "Authors in this Library"
msgstr "Auteurs dans la bibliothèque"
#: cps/templates/stats.html:45
#: cps/templates/stats.html:16
msgid "Categories in this Library"
msgstr ""
#: cps/templates/stats.html:49
#: cps/templates/stats.html:20
msgid "Series in this Library"
msgstr ""
#: cps/templates/stats.html:24
msgid "Linked libraries"
msgstr ""
#: cps/templates/stats.html:28
msgid "Program library"
msgstr ""
#: cps/templates/stats.html:29
msgid "Installed Version"
msgstr ""
#: cps/templates/user_edit.html:23
msgid "Kindle E-Mail"
msgstr "Courriel Kindle"
@@ -958,43 +1059,47 @@ msgstr "Montrer les livres dans la langue"
msgid "Show all"
msgstr "Montrer tout"
#: cps/templates/user_edit.html:45
#: cps/templates/user_edit.html:47
msgid "Show random books"
msgstr "Montrer des livres au hasard"
#: cps/templates/user_edit.html:49
#: cps/templates/user_edit.html:51
msgid "Show hot books"
msgstr "Montrer les livres populaires"
#: cps/templates/user_edit.html:53
#: cps/templates/user_edit.html:55
msgid "Show best rated books"
msgstr ""
#: cps/templates/user_edit.html:57
#: cps/templates/user_edit.html:59
msgid "Show language selection"
msgstr "Montrer la sélection de la langue"
#: cps/templates/user_edit.html:61
#: cps/templates/user_edit.html:63
msgid "Show series selection"
msgstr "Montrer la sélection des séries"
#: cps/templates/user_edit.html:65
#: cps/templates/user_edit.html:67
msgid "Show category selection"
msgstr "Montrer la sélection des catégories"
#: cps/templates/user_edit.html:69
#: cps/templates/user_edit.html:71
msgid "Show author selection"
msgstr ""
#: cps/templates/user_edit.html:73
#: cps/templates/user_edit.html:75
msgid "Show read and unread"
msgstr ""
#: cps/templates/user_edit.html:79
msgid "Show random books in detail view"
msgstr ""
#: cps/templates/user_edit.html:105
#: cps/templates/user_edit.html:112
msgid "Delete this user"
msgstr "Supprimer cet utilisateur"
#: cps/templates/user_edit.html:116
#: cps/templates/user_edit.html:127
msgid "Recent Downloads"
msgstr "Téléchargements récents"

View File

@@ -15,7 +15,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Calibre-web\n"
"Report-Msgid-Bugs-To: https://github.com/janeczku/calibre-web\n"
"POT-Creation-Date: 2017-02-20 19:47+0100\n"
"POT-Creation-Date: 2017-03-19 19:20+0100\n"
"PO-Revision-Date: 2017-01-06 17:00+0000\n"
"Last-Translator: dalin <dalin.lin@gmail.com>\n"
"Language: zh_Hans_CN\n"
@@ -26,341 +26,354 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.3.4\n"
#: cps/book_formats.py:111 cps/book_formats.py:115 cps/web.py:1030
#: cps/book_formats.py:113 cps/book_formats.py:117 cps/web.py:1244
msgid "not installed"
msgstr "未安装"
#: cps/helper.py:150
#: cps/helper.py:164
#, python-format
msgid "Failed to send mail: %s"
msgstr "发送邮件失败: %s"
#: cps/helper.py:157
#: cps/helper.py:171
msgid "Calibre-web test email"
msgstr "Calibre-web 测试邮件"
#: cps/helper.py:158 cps/helper.py:168
#: cps/helper.py:172 cps/helper.py:184
msgid "This email has been sent via calibre web."
msgstr "此邮件由calibre web发送"
#: cps/helper.py:167 cps/templates/detail.html:130
#: cps/helper.py:181 cps/templates/detail.html:146
msgid "Send to Kindle"
msgstr "发送到Kindle"
#: cps/helper.py:185 cps/helper.py:200
#: cps/helper.py:201 cps/helper.py:216
msgid "Could not find any formats suitable for sending by email"
msgstr "无法找到适合邮件发送的格式"
#: cps/helper.py:194
#: cps/helper.py:210
msgid "Could not convert epub to mobi"
msgstr "无法转换epub到mobi"
#: cps/ub.py:434
#: cps/ub.py:488
msgid "Guest"
msgstr "游客"
#: cps/web.py:734
#: cps/web.py:904
msgid "Requesting update package"
msgstr "正在请求更新包"
#: cps/web.py:735
#: cps/web.py:905
msgid "Downloading update package"
msgstr "正在下载更新包"
#: cps/web.py:736
#: cps/web.py:906
msgid "Unzipping update package"
msgstr "正在解压更新包"
#: cps/web.py:737
#: cps/web.py:907
msgid "Files are replaced"
msgstr "文件已替换"
#: cps/web.py:738
#: cps/web.py:908
msgid "Database connections are closed"
msgstr "数据库连接已关闭"
#: cps/web.py:739
#: cps/web.py:909
msgid "Server is stopped"
msgstr "服务器已停止"
#: cps/web.py:740
#: cps/web.py:910
msgid "Update finished, please press okay and reload page"
msgstr "更新完成,请按确定并刷新页面"
#: cps/web.py:810
#: cps/web.py:983
msgid "Latest Books"
msgstr "最新书籍"
#: cps/web.py:835
#: cps/web.py:1014
msgid "Hot Books (most downloaded)"
msgstr "热门书籍(最多下载)"
#: cps/web.py:845
#: cps/web.py:1024
msgid "Best rated books"
msgstr "最高评分书籍"
#: cps/templates/index.xml:36 cps/web.py:854
#: cps/templates/index.xml:36 cps/web.py:1033
msgid "Random Books"
msgstr "随机书籍"
#: cps/web.py:867
#: cps/web.py:1046
msgid "Author list"
msgstr "作者列表"
#: cps/web.py:878
#, python-forma
#: cps/web.py:1057
#, python-forma, python-format
msgid "Author: %(name)s"
msgstr "作者: %(name)s"
#: cps/web.py:880 cps/web.py:908 cps/web.py:1007 cps/web.py:1235
#: cps/web.py:2115
#: cps/web.py:1059 cps/web.py:1087 cps/web.py:1221 cps/web.py:1626
#: cps/web.py:2579
msgid "Error opening eBook. File does not exist or file is not accessible:"
msgstr "无法打开电子书。 文件不存在或者文件不可访问:"
#: cps/templates/index.xml:57 cps/web.py:894
#: cps/templates/index.xml:71 cps/web.py:1073
msgid "Series list"
msgstr "丛书列表"
#: cps/web.py:906
#: cps/web.py:1085
#, python-format
msgid "Series: %(serie)s"
msgstr "丛书: %(serie)s"
#: cps/web.py:939
#: cps/web.py:1118
msgid "Available languages"
msgstr "可用语言"
#: cps/web.py:954
#: cps/web.py:1133
#, python-format
msgid "Language: %(name)s"
msgstr "语言: %(name)s"
#: cps/templates/index.xml:50 cps/web.py:967
#: cps/templates/index.xml:64 cps/web.py:1146
msgid "Category list"
msgstr "分类列表"
#: cps/web.py:979
#: cps/web.py:1158
#, python-format
msgid "Category: %(name)s"
msgstr "分类: %(name)s"
#: cps/web.py:1040
#: cps/web.py:1267
msgid "Statistics"
msgstr "统计"
#: cps/web.py:1061
#: cps/web.py:1375
msgid "Server restarted, please reload page"
msgstr "服务器已重启,请刷新页面"
#: cps/web.py:1063
#: cps/web.py:1377
msgid "Performing shutdown of server, please close window"
msgstr "正在关闭服务器,请关闭窗口"
#: cps/web.py:1073
#: cps/web.py:1392
msgid "Update done"
msgstr "更新完成"
#: cps/web.py:1147 cps/web.py:1160
#: cps/web.py:1470 cps/web.py:1483
msgid "search"
msgstr "搜索"
#: cps/web.py:1211 cps/web.py:1218 cps/web.py:1225 cps/web.py:1232
#: cps/web.py:1602 cps/web.py:1609 cps/web.py:1616 cps/web.py:1623
msgid "Read a Book"
msgstr "阅读一本书"
#: cps/web.py:1276 cps/web.py:1713
#: cps/web.py:1676 cps/web.py:2152
msgid "Please fill out all fields!"
msgstr "请填写所有字段"
#: cps/web.py:1277 cps/web.py:1293 cps/web.py:1298 cps/web.py:1300
#: cps/web.py:1677 cps/web.py:1693 cps/web.py:1698 cps/web.py:1700
msgid "register"
msgstr "注册"
#: cps/web.py:1292
#: cps/web.py:1692
msgid "An unknown error occured. Please try again later."
msgstr "发生一个未知错误。请稍后再试。"
#: cps/web.py:1297
#: cps/web.py:1697
msgid "This username or email address is already in use."
msgstr "此用户名或邮箱已被使用。"
#: cps/web.py:1315
#: cps/web.py:1715
#, python-format
msgid "you are now logged in as: '%(nickname)s'"
msgstr "您现在已以'%(nickname)s'身份登录"
#: cps/web.py:1320
#: cps/web.py:1720
msgid "Wrong Username or Password"
msgstr "用户名或密码错误"
#: cps/web.py:1322
#: cps/web.py:1722
msgid "login"
msgstr "登录"
#: cps/web.py:1339
#: cps/web.py:1739
msgid "Please configure the SMTP mail settings first..."
msgstr "请先配置SMTP邮箱..."
#: cps/web.py:1343
#: cps/web.py:1743
#, python-format
msgid "Book successfully send to %(kindlemail)s"
msgstr "此书已被成功发给 %(kindlemail)s"
#: cps/web.py:1347
#: cps/web.py:1747
#, python-format
msgid "There was an error sending this book: %(res)s"
msgstr "发送这本书的时候出现错误: %(res)s"
#: cps/web.py:1349
#: cps/web.py:1749 cps/web.py:2232
msgid "Please configure your kindle email address first..."
msgstr "请先配置您的kindle电子邮箱地址..."
#: cps/web.py:1369
#: cps/web.py:1774
#, python-format
msgid "Book has been added to shelf: %(sname)s"
msgstr "此书已被添加到书架: %(sname)s"
#: cps/web.py:1390
#: cps/web.py:1793
#, python-format
msgid "Book has been removed from shelf: %(sname)s"
msgstr "此书已从书架 %(sname)s 中删除"
#: cps/web.py:1409 cps/web.py:1433
#: cps/web.py:1812 cps/web.py:1836
#, python-format
msgid "A shelf with the name '%(title)s' already exists."
msgstr "已存在书架 '%(title)s'。"
#: cps/web.py:1414
#: cps/web.py:1817
#, python-format
msgid "Shelf %(title)s created"
msgstr "书架 %(title)s 已被创建"
#: cps/web.py:1416 cps/web.py:1444
#: cps/web.py:1819 cps/web.py:1847
msgid "There was an error"
msgstr "发生错误"
#: cps/web.py:1417 cps/web.py:1419
#: cps/web.py:1820 cps/web.py:1822
msgid "create a shelf"
msgstr "创建书架"
#: cps/web.py:1442
#: cps/web.py:1845
#, python-format
msgid "Shelf %(title)s changed"
msgstr "书架 %(title)s 已被修改"
#: cps/web.py:1445 cps/web.py:1447
#: cps/web.py:1848 cps/web.py:1850
msgid "Edit a shelf"
msgstr "编辑书架"
#: cps/web.py:1465
#: cps/web.py:1868
#, python-format
msgid "successfully deleted shelf %(name)s"
msgstr "成功删除书架 %(name)s"
#: cps/web.py:1487
#: cps/web.py:1890
#, python-format
msgid "Shelf: '%(name)s'"
msgstr "书架: '%(name)s'"
#: cps/web.py:1518
#: cps/web.py:1921
#, python-format
msgid "Change order of Shelf: '%(name)s'"
msgstr "修改书架 '%(name)s' 顺序"
#: cps/web.py:1580
#: cps/web.py:1985
msgid "Found an existing account for this email address."
msgstr "找到已使用此邮箱的账号。"
#: cps/web.py:1582 cps/web.py:1586
#: cps/web.py:1987 cps/web.py:1991
#, python-format
msgid "%(name)s's profile"
msgstr "%(name)s 的资料"
#: cps/web.py:1583
#: cps/web.py:1988
msgid "Profile updated"
msgstr "资料已更新"
#: cps/web.py:1597
#: cps/web.py:2002
msgid "Admin page"
msgstr "管理页"
#: cps/web.py:1668
#: cps/web.py:2106
msgid "Calibre-web configuration updated"
msgstr "Calibre-web配置已更新"
#: cps/web.py:1675 cps/web.py:1681 cps/web.py:1694
#: cps/web.py:2113 cps/web.py:2119 cps/web.py:2133
msgid "Basic Configuration"
msgstr "基本配置"
#: cps/web.py:1679
#: cps/web.py:2117
msgid "DB location is not valid, please enter correct path"
msgstr "DB位置无效请输入正确路径"
#: cps/templates/admin.html:34 cps/web.py:1715 cps/web.py:1761
#: cps/templates/admin.html:34 cps/web.py:2154 cps/web.py:2202
msgid "Add new user"
msgstr "添加新用户"
#: cps/web.py:1753
#: cps/web.py:2194
#, python-format
msgid "User '%(user)s' created"
msgstr "用户 '%(user)s' 已被创建"
#: cps/web.py:1757
#: cps/web.py:2198
msgid "Found an existing account for this email address or nickname."
msgstr "已找到使用此邮箱或昵称的账号。"
#: cps/web.py:1779
#: cps/web.py:2220
msgid "Mail settings updated"
msgstr "邮箱设置已更新"
#: cps/web.py:1785
#: cps/web.py:2227
#, python-format
msgid "Test E-Mail successfully send to %(kindlemail)s"
msgstr "测试邮件已成功发送到 %(kindlemail)s"
#: cps/web.py:1788
#: cps/web.py:2230
#, python-format
msgid "There was an error sending the Test E-Mail: %(res)s"
msgstr "发送测试邮件时发生错误: %(res)s"
#: cps/web.py:1789
#: cps/web.py:2234
msgid "E-Mail settings updated"
msgstr "E-Mail 设置已更新"
#: cps/web.py:2235
msgid "Edit mail settings"
msgstr "编辑邮箱设置"
#: cps/web.py:1817
#: cps/web.py:2263
#, python-format
msgid "User '%(nick)s' deleted"
msgstr "用户 '%(nick)s' 已被删除"
#: cps/web.py:1898
#: cps/web.py:2349
#, python-format
msgid "User '%(nick)s' updated"
msgstr "用户 '%(nick)s' 已被更新"
#: cps/web.py:1901
#: cps/web.py:2352
msgid "An unknown error occured."
msgstr "发生未知错误。"
#: cps/web.py:1904
#: cps/web.py:2355
#, python-format
msgid "Edit User %(nick)s"
msgstr "编辑用户 %(nick)s"
#: cps/web.py:2110 cps/web.py:2113 cps/web.py:2188
#: cps/web.py:2574 cps/web.py:2577 cps/web.py:2689
msgid "edit metadata"
msgstr "编辑元数据"
#: cps/web.py:2145
#: cps/web.py:2598
#, python-format
msgid "File extension \"%s\" is not allowed to be uploaded to this server"
msgstr "不能上传后缀为 \"%s\" 的文件到此服务器"
#: cps/web.py:2604
msgid "File to be uploaded must have an extension"
msgstr "要上传的文件必须有一个后缀"
#: cps/web.py:2621
#, python-format
msgid "Failed to create path %s (Permission denied)."
msgstr "创建路径 %s 失败(权限拒绝)。"
#: cps/web.py:2150
#: cps/web.py:2626
#, python-format
msgid "Failed to store file %s (Permission denied)."
msgstr "存储文件 %s 失败(权限拒绝)。"
#: cps/web.py:2155
#: cps/web.py:2631
#, python-format
msgid "Failed to delete file %s (Permission denied)."
msgstr "删除文件 %s 失败(权限拒绝)。"
@@ -389,7 +402,7 @@ msgstr ""
msgid "Admin"
msgstr "管理"
#: cps/templates/admin.html:13 cps/templates/detail.html:117
#: cps/templates/admin.html:13 cps/templates/detail.html:134
msgid "Download"
msgstr "下载"
@@ -445,7 +458,7 @@ msgstr "配置"
msgid "Calibre DB dir"
msgstr "Calibre DB目录"
#: cps/templates/admin.html:61 cps/templates/config_edit.html:32
#: cps/templates/admin.html:61 cps/templates/config_edit.html:76
msgid "Log Level"
msgstr "日志级别"
@@ -453,7 +466,7 @@ msgstr "日志级别"
msgid "Port"
msgstr "端口"
#: cps/templates/admin.html:63 cps/templates/config_edit.html:19
#: cps/templates/admin.html:63 cps/templates/config_edit.html:60
msgid "Books per page"
msgstr "每页书籍数"
@@ -482,42 +495,46 @@ msgid "Newest commit timestamp"
msgstr "最新提交时间戳"
#: cps/templates/admin.html:83
msgid "Reconnect to Calibre DB"
msgstr ""
#: cps/templates/admin.html:84
msgid "Restart Calibre-web"
msgstr "重启 Calibre-web"
#: cps/templates/admin.html:84
#: cps/templates/admin.html:85
msgid "Stop Calibre-web"
msgstr "停止 Calibre-web"
#: cps/templates/admin.html:85
#: cps/templates/admin.html:86
msgid "Check for update"
msgstr "检查更新"
#: cps/templates/admin.html:86
#: cps/templates/admin.html:87
msgid "Perform Update"
msgstr "执行更新"
#: cps/templates/admin.html:96
#: cps/templates/admin.html:97
msgid "Do you really want to restart Calibre-web?"
msgstr "您确定要重启 Calibre-web 吗?"
#: cps/templates/admin.html:101 cps/templates/admin.html:115
#: cps/templates/admin.html:136
#: cps/templates/admin.html:102 cps/templates/admin.html:116
#: cps/templates/admin.html:137
msgid "Ok"
msgstr "确定"
#: cps/templates/admin.html:102 cps/templates/admin.html:116
#: cps/templates/book_edit.html:108 cps/templates/config_edit.html:75
#: cps/templates/admin.html:103 cps/templates/admin.html:117
#: cps/templates/book_edit.html:109 cps/templates/config_edit.html:119
#: cps/templates/email_edit.html:36 cps/templates/shelf_edit.html:17
#: cps/templates/shelf_order.html:12 cps/templates/user_edit.html:111
#: cps/templates/shelf_order.html:12 cps/templates/user_edit.html:120
msgid "Back"
msgstr "后退"
#: cps/templates/admin.html:114
#: cps/templates/admin.html:115
msgid "Do you really want to stop Calibre-web?"
msgstr "您确定要关闭 Calibre-web 吗?"
#: cps/templates/admin.html:127
#: cps/templates/admin.html:128
msgid "Updating, please do not reload page"
msgstr "正在更新,请不要刷新页面"
@@ -525,20 +542,21 @@ msgstr "正在更新,请不要刷新页面"
msgid "Book Title"
msgstr "书名"
#: cps/templates/book_edit.html:20 cps/templates/search_form.html:10
#: cps/templates/book_edit.html:20 cps/templates/book_edit.html:145
#: cps/templates/search_form.html:10
msgid "Author"
msgstr "作者"
#: cps/templates/book_edit.html:24
#: cps/templates/book_edit.html:24 cps/templates/book_edit.html:147
msgid "Description"
msgstr "简介"
#: cps/templates/book_edit.html:28 cps/templates/search_form.html:13
#: cps/templates/book_edit.html:28 cps/templates/search_form.html:17
msgid "Tags"
msgstr "标签"
#: cps/templates/book_edit.html:33 cps/templates/layout.html:138
#: cps/templates/search_form.html:33
#: cps/templates/book_edit.html:33 cps/templates/layout.html:142
#: cps/templates/search_form.html:37
msgid "Series"
msgstr "丛书"
@@ -570,69 +588,142 @@ msgstr ""
msgid "view book after edit"
msgstr "编辑后查看书籍"
#: cps/templates/book_edit.html:107 cps/templates/config_edit.html:73
#: cps/templates/login.html:19 cps/templates/search_form.html:75
#: cps/templates/shelf_edit.html:15 cps/templates/user_edit.html:109
#: cps/templates/book_edit.html:107 cps/templates/book_edit.html:118
msgid "Get metadata"
msgstr ""
#: 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/shelf_edit.html:15 cps/templates/user_edit.html:118
msgid "Submit"
msgstr "提交"
#: cps/templates/book_edit.html:121
msgid "Keyword"
msgstr ""
#: cps/templates/book_edit.html:122
msgid " Search keyword "
msgstr ""
#: cps/templates/book_edit.html:124 cps/templates/layout.html:60
msgid "Go!"
msgstr "走起!"
#: cps/templates/book_edit.html:125
msgid "Click the cover to load metadata to the form"
msgstr ""
#: cps/templates/book_edit.html:129 cps/templates/book_edit.html:142
msgid "Loading..."
msgstr ""
#: cps/templates/book_edit.html:132
msgid "Close"
msgstr ""
#: cps/templates/book_edit.html:143
msgid "Search error!"
msgstr ""
#: cps/templates/book_edit.html:144
msgid "No Result! Please try anonther keyword."
msgstr ""
#: cps/templates/book_edit.html:146 cps/templates/detail.html:76
#: cps/templates/search_form.html:14
msgid "Publisher"
msgstr ""
#: cps/templates/book_edit.html:148
msgid "Source"
msgstr ""
#: cps/templates/config_edit.html:7
msgid "Location of Calibre database"
msgstr "Calibre 数据库位置"
#: cps/templates/config_edit.html:11
#: cps/templates/config_edit.html:13
msgid "Use google drive?"
msgstr ""
#: cps/templates/config_edit.html:17
msgid "Client id"
msgstr ""
#: cps/templates/config_edit.html:21
msgid "Client secret"
msgstr ""
#: cps/templates/config_edit.html:25
msgid "Calibre Base URL"
msgstr ""
#: cps/templates/config_edit.html:29
msgid "Google drive Calibre folder"
msgstr ""
#: cps/templates/config_edit.html:38
msgid "Metadata Watch Channel ID"
msgstr ""
#: cps/templates/config_edit.html:52
msgid "Server Port"
msgstr "服务器端口"
#: cps/templates/config_edit.html:15 cps/templates/shelf_edit.html:7
#: cps/templates/config_edit.html:56 cps/templates/shelf_edit.html:7
msgid "Title"
msgstr "标题"
#: cps/templates/config_edit.html:23
#: cps/templates/config_edit.html:64
msgid "No. of random books to show"
msgstr "随机书籍显示数量"
#: cps/templates/config_edit.html:28
#: cps/templates/config_edit.html:68
msgid "Regular expression for ignoring columns"
msgstr ""
#: cps/templates/config_edit.html:72
msgid "Regular expression for title sorting"
msgstr "标题排序的正则表达式"
#: cps/templates/config_edit.html:42
#: cps/templates/config_edit.html:86
msgid "Enable uploading"
msgstr "启用上传"
#: cps/templates/config_edit.html:46
#: cps/templates/config_edit.html:90
msgid "Enable anonymous browsing"
msgstr "启用匿名浏览"
#: cps/templates/config_edit.html:50
#: cps/templates/config_edit.html:94
msgid "Enable public registration"
msgstr "启用注册"
#: cps/templates/config_edit.html:52
#: cps/templates/config_edit.html:96
msgid "Default Settings for new users"
msgstr "新用户默认设置"
#: cps/templates/config_edit.html:55 cps/templates/user_edit.html:80
#: cps/templates/config_edit.html:99 cps/templates/user_edit.html:87
msgid "Admin user"
msgstr "管理用户"
#: cps/templates/config_edit.html:59 cps/templates/user_edit.html:85
#: cps/templates/config_edit.html:103 cps/templates/user_edit.html:92
msgid "Allow Downloads"
msgstr "允许下载"
#: cps/templates/config_edit.html:63 cps/templates/user_edit.html:89
#: cps/templates/config_edit.html:107 cps/templates/user_edit.html:96
msgid "Allow Uploads"
msgstr "允许上传"
#: cps/templates/config_edit.html:67 cps/templates/user_edit.html:93
#: cps/templates/config_edit.html:111 cps/templates/user_edit.html:100
msgid "Allow Edit"
msgstr "允许编辑"
#: cps/templates/config_edit.html:71 cps/templates/user_edit.html:98
#: cps/templates/config_edit.html:115 cps/templates/user_edit.html:105
msgid "Allow Changing Password"
msgstr "允许修改密码"
#: cps/templates/config_edit.html:78 cps/templates/layout.html:93
#: cps/templates/config_edit.html:122 cps/templates/layout.html:93
#: cps/templates/login.html:4
msgid "Login"
msgstr "登录"
@@ -649,23 +740,27 @@ msgstr ""
msgid "language"
msgstr "语言"
#: cps/templates/detail.html:74
#: cps/templates/detail.html:81
msgid "Publishing date"
msgstr "出版日期"
#: cps/templates/detail.html:106
#: cps/templates/detail.html:115
msgid "Read"
msgstr ""
#: cps/templates/detail.html:123
msgid "Description:"
msgstr "简介:"
#: cps/templates/detail.html:134
#: cps/templates/detail.html:151
msgid "Read in browser"
msgstr "在浏览器中阅读"
#: cps/templates/detail.html:154
#: cps/templates/detail.html:171
msgid "Add to shelf"
msgstr "添加到书架"
#: cps/templates/detail.html:194
#: cps/templates/detail.html:211
msgid "Edit metadata"
msgstr "编辑元数据"
@@ -745,19 +840,29 @@ msgstr "最新书籍"
msgid "Show Random Books"
msgstr "显示随机书籍"
#: cps/templates/index.xml:43 cps/templates/layout.html:140
#: cps/templates/index.xml:43 cps/templates/index.xml:47
#: cps/templates/layout.html:132
msgid "Read Books"
msgstr ""
#: cps/templates/index.xml:50 cps/templates/index.xml:54
#: cps/templates/layout.html:133
msgid "Unread Books"
msgstr ""
#: cps/templates/index.xml:57 cps/templates/layout.html:144
msgid "Authors"
msgstr "作者"
#: cps/templates/index.xml:47
#: cps/templates/index.xml:61
msgid "Books ordered by Author"
msgstr "书籍按作者排序"
#: cps/templates/index.xml:54
#: cps/templates/index.xml:68
msgid "Books ordered by category"
msgstr "书籍按分类排序"
#: cps/templates/index.xml:61
#: cps/templates/index.xml:75
msgid "Books ordered by series"
msgstr "书籍按丛书排序"
@@ -765,10 +870,6 @@ msgstr "书籍按丛书排序"
msgid "Toggle navigation"
msgstr "切换导航"
#: cps/templates/layout.html:60
msgid "Go!"
msgstr "走起!"
#: cps/templates/layout.html:68
msgid "Advanced Search"
msgstr "高级搜索"
@@ -785,31 +886,31 @@ msgstr "注册"
msgid "Browse"
msgstr "浏览"
#: cps/templates/layout.html:132
#: cps/templates/layout.html:136
msgid "Discover"
msgstr "发现"
#: cps/templates/layout.html:135
#: cps/templates/layout.html:139
msgid "Categories"
msgstr "分类"
#: cps/templates/layout.html:142 cps/templates/search_form.html:54
#: cps/templates/layout.html:146 cps/templates/search_form.html:58
msgid "Languages"
msgstr "语言"
#: cps/templates/layout.html:145
#: cps/templates/layout.html:149
msgid "Public Shelves"
msgstr "公开书架"
#: cps/templates/layout.html:149
#: cps/templates/layout.html:153
msgid "Your Shelves"
msgstr "您的书架"
#: cps/templates/layout.html:154
#: cps/templates/layout.html:158
msgid "Create a Shelf"
msgstr "创建书架"
#: cps/templates/layout.html:155
#: cps/templates/layout.html:159
msgid "About"
msgstr "关于"
@@ -875,15 +976,15 @@ msgstr "请尝试别的关键字"
msgid "Results for:"
msgstr "结果:"
#: cps/templates/search_form.html:23
#: cps/templates/search_form.html:27
msgid "Exclude Tags"
msgstr "排除标签"
#: cps/templates/search_form.html:43
#: cps/templates/search_form.html:47
msgid "Exclude Series"
msgstr "排除丛书"
#: cps/templates/search_form.html:64
#: cps/templates/search_form.html:68
msgid "Exclude Languages"
msgstr "排除语言"
@@ -908,37 +1009,37 @@ msgid "Drag 'n drop to rearrange order"
msgstr "拖拽以重新排序"
#: cps/templates/stats.html:3
msgid "Linked libraries"
msgstr "链接库"
#: cps/templates/stats.html:8
msgid "Program library"
msgstr "程序库"
#: cps/templates/stats.html:9
msgid "Installed Version"
msgstr "已安装版本"
#: cps/templates/stats.html:32
msgid "Calibre library statistics"
msgstr "Calibre书库统计"
#: cps/templates/stats.html:37
#: cps/templates/stats.html:8
msgid "Books in this Library"
msgstr "本书在此书库"
#: cps/templates/stats.html:41
#: cps/templates/stats.html:12
msgid "Authors in this Library"
msgstr "个作者在此书库"
#: cps/templates/stats.html:45
#: cps/templates/stats.html:16
msgid "Categories in this Library"
msgstr "个分类在此书库"
#: cps/templates/stats.html:49
#: cps/templates/stats.html:20
msgid "Series in this Library"
msgstr "个丛书在此书库"
#: cps/templates/stats.html:24
msgid "Linked libraries"
msgstr "链接库"
#: cps/templates/stats.html:28
msgid "Program library"
msgstr "程序库"
#: cps/templates/stats.html:29
msgid "Installed Version"
msgstr "已安装版本"
#: cps/templates/user_edit.html:23
msgid "Kindle E-Mail"
msgstr ""
@@ -951,43 +1052,47 @@ msgstr "按语言显示书籍"
msgid "Show all"
msgstr "显示全部"
#: cps/templates/user_edit.html:45
#: cps/templates/user_edit.html:47
msgid "Show random books"
msgstr "显示随机书籍"
#: cps/templates/user_edit.html:49
#: cps/templates/user_edit.html:51
msgid "Show hot books"
msgstr "显示热门书籍"
#: cps/templates/user_edit.html:53
#: cps/templates/user_edit.html:55
msgid "Show best rated books"
msgstr "显示最高评分书籍"
#: cps/templates/user_edit.html:57
#: cps/templates/user_edit.html:59
msgid "Show language selection"
msgstr "显示语言选择"
#: cps/templates/user_edit.html:61
#: cps/templates/user_edit.html:63
msgid "Show series selection"
msgstr "显示丛书选择"
#: cps/templates/user_edit.html:65
#: cps/templates/user_edit.html:67
msgid "Show category selection"
msgstr "显示分类选择"
#: cps/templates/user_edit.html:69
#: cps/templates/user_edit.html:71
msgid "Show author selection"
msgstr "显示作者选择"
#: cps/templates/user_edit.html:73
#: cps/templates/user_edit.html:75
msgid "Show read and unread"
msgstr ""
#: cps/templates/user_edit.html:79
msgid "Show random books in detail view"
msgstr "在详情页显示随机书籍"
#: cps/templates/user_edit.html:105
#: cps/templates/user_edit.html:112
msgid "Delete this user"
msgstr "删除此用户"
#: cps/templates/user_edit.html:116
#: cps/templates/user_edit.html:127
msgid "Recent Downloads"
msgstr "最近下载"

View File

@@ -10,6 +10,8 @@ import os
import logging
from werkzeug.security import generate_password_hash
from flask_babel import gettext as _
import json
#from builtins import str
dbpath = os.path.join(os.path.normpath(os.path.dirname(os.path.realpath(__file__)) + os.sep + ".." + os.sep), "app.db")
engine = create_engine('sqlite:///{0}'.format(dbpath), echo=False)
@@ -22,6 +24,7 @@ ROLE_UPLOAD = 4
ROLE_EDIT = 8
ROLE_PASSWD = 16
ROLE_ANONYMOUS = 32
ROLE_EDIT_SHELFS = 64
DETAIL_RANDOM = 1
SIDEBAR_LANGUAGE = 2
@@ -31,6 +34,7 @@ SIDEBAR_HOT = 16
SIDEBAR_RANDOM = 32
SIDEBAR_AUTHOR = 64
SIDEBAR_BEST_RATED = 128
SIDEBAR_READ_AND_UNREAD = 256
DEFAULT_PASS = "admin123"
DEFAULT_PORT = int(os.environ.get("CALIBRE_PORT", 8083))
@@ -83,6 +87,12 @@ class UserBase:
else:
return False
def role_edit_shelfs(self):
if self.role is not None:
return True if self.role & ROLE_EDIT_SHELFS == ROLE_EDIT_SHELFS else False
else:
return False
def is_active(self):
return True
@@ -90,7 +100,7 @@ class UserBase:
return False
def get_id(self):
return unicode(self.id)
return str(self.id)
def filter_language(self):
return self.default_language
@@ -137,6 +147,12 @@ class UserBase:
else:
return False
def show_read_and_unread(self):
if self.sidebar_view is not None:
return True if self.sidebar_view & SIDEBAR_READ_AND_UNREAD == SIDEBAR_READ_AND_UNREAD else False
else:
return False
def show_detail_random(self):
if self.sidebar_view is not None:
return True if self.sidebar_view & DETAIL_RANDOM == DETAIL_RANDOM else False
@@ -178,7 +194,6 @@ class Anonymous(AnonymousUserMixin, UserBase):
self.role = data.role
self.sidebar_view = data.sidebar_view
self.default_language = data.default_language
self.default_language = data.default_language
self.locale = data.locale
self.anon_browse = settings.config_anonbrowse
@@ -217,6 +232,14 @@ class BookShelf(Base):
def __repr__(self):
return '<Book %r>' % self.id
class ReadBook(Base):
__tablename__ = 'book_read_link'
id=Column(Integer, primary_key=True)
book_id = Column(Integer, unique=False)
user_id =Column(Integer, ForeignKey('user.id'), unique=False)
is_read = Column(Boolean, unique=False)
# Baseclass representing Downloads from calibre-web in app.db
class Downloads(Base):
@@ -253,6 +276,14 @@ class Settings(Base):
config_anonbrowse = Column(SmallInteger, default=0)
config_public_reg = Column(SmallInteger, default=0)
config_default_role = Column(SmallInteger, default=0)
config_columns_to_ignore = Column(String)
config_use_google_drive = Column(Boolean)
config_google_drive_client_id = Column(String)
config_google_drive_client_secret = Column(String)
config_google_drive_folder = Column(String)
config_google_drive_calibre_url_base = Column(String)
config_google_drive_watch_changes_response = Column(String)
config_columns_to_ignore = Column(String)
def __repr__(self):
pass
@@ -279,7 +310,18 @@ class Config:
self.config_anonbrowse = data.config_anonbrowse
self.config_public_reg = data.config_public_reg
self.config_default_role = data.config_default_role
if self.config_calibre_dir is not None:
self.config_columns_to_ignore = data.config_columns_to_ignore
self.config_use_google_drive = data.config_use_google_drive
self.config_google_drive_client_id = data.config_google_drive_client_id
self.config_google_drive_client_secret = data.config_google_drive_client_secret
self.config_google_drive_calibre_url_base = data.config_google_drive_calibre_url_base
self.config_google_drive_folder = data.config_google_drive_folder
if data.config_google_drive_watch_changes_response:
self.config_google_drive_watch_changes_response = json.loads(data.config_google_drive_watch_changes_response)
else:
self.config_google_drive_watch_changes_response=None
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 = True
else:
self.db_configured = False
@@ -318,6 +360,12 @@ class Config:
else:
return False
def role_edit_shelfs(self):
if self.config_default_role is not None:
return True if self.config_default_role & ROLE_EDIT_SHELFS == ROLE_EDIT_SHELFS else False
else:
return False
def get_Log_Level(self):
ret_value=""
if self.config_log_level == logging.INFO:
@@ -335,6 +383,9 @@ class Config:
# everywhere to curent should work. Migration is done by checking if relevant coloums are existing, and than adding
# rows with SQL commands
def migrate_Database():
if not engine.dialect.has_table(engine.connect(), "book_read_link"):
ReadBook.__table__.create(bind = engine)
try:
session.query(exists().where(User.locale)).scalar()
session.commit()
@@ -360,6 +411,23 @@ def migrate_Database():
conn.execute("ALTER TABLE Settings ADD column `config_anonbrowse` SmallInteger DEFAULT 0")
conn.execute("ALTER TABLE Settings ADD column `config_public_reg` SmallInteger DEFAULT 0")
session.commit()
try:
session.query(exists().where(Settings.config_use_google_drive)).scalar()
except exc.OperationalError:
conn = engine.connect()
conn.execute("ALTER TABLE Settings ADD column `config_use_google_drive` INTEGER DEFAULT 0")
conn.execute("ALTER TABLE Settings ADD column `config_google_drive_client_id` String DEFAULT ''")
conn.execute("ALTER TABLE Settings ADD column `config_google_drive_client_secret` String DEFAULT ''")
conn.execute("ALTER TABLE Settings ADD column `config_google_drive_calibre_url_base` INTEGER DEFAULT 0")
conn.execute("ALTER TABLE Settings ADD column `config_google_drive_folder` String DEFAULT ''")
conn.execute("ALTER TABLE Settings ADD column `config_google_drive_watch_changes_response` String DEFAULT ''")
try:
session.query(exists().where(Settings.config_columns_to_ignore)).scalar()
except exc.OperationalError:
conn = engine.connect()
conn.execute("ALTER TABLE Settings ADD column `config_columns_to_ignore` String DEFAULT ''")
session.commit()
try:
session.query(exists().where(Settings.config_default_role)).scalar()
session.commit()
@@ -438,7 +506,7 @@ def create_anonymous_user():
session.add(user)
try:
session.commit()
except:
except Exception as e:
session.rollback()
pass
@@ -449,14 +517,15 @@ def create_admin_user():
user.nickname = "admin"
user.role = ROLE_USER + ROLE_ADMIN + ROLE_DOWNLOAD + ROLE_UPLOAD + ROLE_EDIT + ROLE_PASSWD
user.sidebar_view = DETAIL_RANDOM + SIDEBAR_LANGUAGE + SIDEBAR_SERIES + SIDEBAR_CATEGORY + SIDEBAR_HOT + \
SIDEBAR_RANDOM + SIDEBAR_AUTHOR + SIDEBAR_BEST_RATED
SIDEBAR_RANDOM + SIDEBAR_AUTHOR + SIDEBAR_BEST_RATED + SIDEBAR_READ_AND_UNREAD
user.password = generate_password_hash(DEFAULT_PASS)
session.add(user)
try:
session.commit()
except:
except Exception as e:
session.rollback()
pass

View File

@@ -7,7 +7,7 @@ import hashlib
from collections import namedtuple
import book_formats
BookMeta = namedtuple('BookMeta', 'file_path, extension, title, author, cover, description, tags, series, series_id')
BookMeta = namedtuple('BookMeta', 'file_path, extension, title, author, cover, description, tags, series, series_id, languages')
"""
:rtype: BookMeta

File diff suppressed because it is too large Load Diff