mirror of
https://github.com/janeczku/calibre-web
synced 2024-12-25 17:40:31 +00:00
commit
2272013d80
10
cps/db.py
10
cps/db.py
@ -11,7 +11,7 @@ from ub import config
|
||||
import ub
|
||||
|
||||
session = None
|
||||
cc_exceptions = ['datetime', 'int', 'comments', 'float', 'composite', 'series']
|
||||
cc_exceptions = ['datetime', 'comments', 'float', 'composite', 'series']
|
||||
cc_classes = None
|
||||
engine = None
|
||||
|
||||
@ -302,7 +302,6 @@ def setup_db():
|
||||
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:///'+ dbpath, echo=False, isolation_level="SERIALIZABLE")
|
||||
try:
|
||||
conn = engine.connect()
|
||||
@ -340,6 +339,11 @@ def setup_db():
|
||||
'id': Column(Integer, primary_key=True),
|
||||
'book': Column(Integer, ForeignKey('books.id')),
|
||||
'value': Column(Boolean)}
|
||||
elif row.datatype == 'int':
|
||||
ccdict = {'__tablename__': 'custom_column_' + str(row.id),
|
||||
'id': Column(Integer, primary_key=True),
|
||||
'book': Column(Integer, ForeignKey('books.id')),
|
||||
'value': Column(Integer)}
|
||||
else:
|
||||
ccdict = {'__tablename__': 'custom_column_' + str(row.id),
|
||||
'id': Column(Integer, primary_key=True),
|
||||
@ -347,7 +351,7 @@ def setup_db():
|
||||
cc_classes[row.id] = type('Custom_Column_' + str(row.id), (Base,), ccdict)
|
||||
|
||||
for cc_id in cc_ids:
|
||||
if cc_id[1] == 'bool':
|
||||
if (cc_id[1] == 'bool') or (cc_id[1] == 'int'):
|
||||
setattr(Books, 'custom_column_' + str(cc_id[0]), relationship(cc_classes[cc_id[0]],
|
||||
primaryjoin=(
|
||||
Books.id == cc_classes[cc_id[0]].book),
|
||||
|
@ -52,6 +52,9 @@ except Exception as e:
|
||||
global_task = None
|
||||
updater_thread = None
|
||||
|
||||
RET_SUCCESS = 1
|
||||
RET_FAIL = 0
|
||||
|
||||
def update_download(book_id, user_id):
|
||||
check = ub.session.query(ub.Downloads).filter(ub.Downloads.user_id == user_id).filter(ub.Downloads.book_id ==
|
||||
book_id).first()
|
||||
@ -63,6 +66,7 @@ def update_download(book_id, user_id):
|
||||
|
||||
|
||||
def make_mobi(book_id, calibrepath):
|
||||
error_message = None
|
||||
vendorpath = os.path.join(os.path.normpath(os.path.dirname(os.path.realpath(__file__)) +
|
||||
os.sep + "../vendor" + os.sep))
|
||||
if sys.platform == "win32":
|
||||
@ -70,24 +74,41 @@ def make_mobi(book_id, calibrepath):
|
||||
else:
|
||||
kindlegen = (os.path.join(vendorpath, u"kindlegen")).encode(sys.getfilesystemencoding())
|
||||
if not os.path.exists(kindlegen):
|
||||
app.logger.error("make_mobi: kindlegen binary not found in: %s" % kindlegen)
|
||||
return None
|
||||
error_message = _(u"kindlegen binary %(kindlepath)s not found", kindlepath=kindlegen)
|
||||
app.logger.error("make_mobi: " + error_message)
|
||||
return error_message, RET_FAIL
|
||||
book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
|
||||
data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == 'EPUB').first()
|
||||
if not data:
|
||||
app.logger.error("make_mobi: epub format not found for book id: %d" % book_id)
|
||||
return None
|
||||
error_message = _(u"epub format not found for book id: %(book)d", book=book_id)
|
||||
app.logger.error("make_mobi: " + error_message)
|
||||
return error_message, RET_FAIL
|
||||
|
||||
file_path = os.path.join(calibrepath, book.path, data.name)
|
||||
if os.path.exists(file_path + u".epub"):
|
||||
p = subprocess.Popen((kindlegen + " \"" + file_path + u".epub\"").encode(sys.getfilesystemencoding()),
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
|
||||
try:
|
||||
p = subprocess.Popen((kindlegen + " \"" + file_path + u".epub\"").encode(sys.getfilesystemencoding()),
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
|
||||
except:
|
||||
error_message = _(u"kindlegen failed, no excecution permissions")
|
||||
app.logger.error("make_mobi: "+error_message)
|
||||
return error_message, RET_FAIL
|
||||
|
||||
# Poll process for new output until finished
|
||||
while True:
|
||||
nextline = p.stdout.readline()
|
||||
if nextline == '' and p.poll() is not None:
|
||||
break
|
||||
if nextline != "\r\n":
|
||||
# Format of error message (kindlegen translates its output texts):
|
||||
# Error(prcgen):E23006: Language not recognized in metadata.The dc:Language field is mandatory.Aborting.
|
||||
conv_error=re.search(".*\(.*\):(E\d+):\s(.*)",nextline)
|
||||
# If error occoures, log in every case
|
||||
if conv_error:
|
||||
error_message = _(u"Kindlegen failed with Error %(error)s. Message: %(message)s",
|
||||
error=conv_error.group(1), message=conv_error.group(2).decode('utf-8'))
|
||||
app.logger.info("make_mobi: " + error_message)
|
||||
app.logger.info(nextline.strip('\r\n'))
|
||||
app.logger.debug(nextline.strip('\r\n'))
|
||||
|
||||
check = p.returncode
|
||||
@ -99,13 +120,13 @@ def make_mobi(book_id, calibrepath):
|
||||
uncompressed_size=os.path.getsize(file_path + ".mobi")
|
||||
))
|
||||
db.session.commit()
|
||||
return file_path + ".mobi"
|
||||
return file_path + ".mobi", RET_SUCCESS
|
||||
else:
|
||||
app.logger.error("make_mobi: kindlegen failed with error while converting book")
|
||||
return None
|
||||
return None, RET_FAIL
|
||||
else:
|
||||
app.logger.error("make_mobie: epub not found: %s.epub" % file_path)
|
||||
return None
|
||||
app.logger.error("make_mobi: epub not found: %s.epub" % file_path)
|
||||
return None, RET_FAIL
|
||||
|
||||
|
||||
class StderrLogger(object):
|
||||
@ -204,13 +225,11 @@ def send_mail(book_id, kindle_mail, calibrepath):
|
||||
if 'mobi' in formats:
|
||||
msg.attach(get_attachment(formats['mobi']))
|
||||
elif 'epub' in formats:
|
||||
filepath = make_mobi(book.id, calibrepath)
|
||||
if filepath is not None:
|
||||
msg.attach(get_attachment(filepath))
|
||||
elif filepath is None:
|
||||
return _("Could not convert epub to mobi")
|
||||
elif 'pdf' in formats:
|
||||
msg.attach(get_attachment(formats['pdf']))
|
||||
data, resultCode = make_mobi(book.id, calibrepath)
|
||||
if resultCode == RET_SUCCESS:
|
||||
msg.attach(get_attachment(data))
|
||||
else:
|
||||
return data #_("Could not convert epub to mobi")
|
||||
elif 'pdf' in formats:
|
||||
msg.attach(get_attachment(formats['pdf']))
|
||||
else:
|
||||
|
@ -51,12 +51,12 @@
|
||||
<label for="cover_url">{{_('Cover URL (jpg)')}}</label>
|
||||
<input type="text" class="form-control" name="cover_url" id="cover_url" value="">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label for="languages">{{_('Language')}}</label>
|
||||
<input type="text" class="form-control typeahead" name="languages" id="languages" value="{% for language in book.languages %}{{language.language_name.strip()}}, {% endfor %}">
|
||||
</div>
|
||||
|
||||
|
||||
{% if cc|length > 0 %}
|
||||
{% for c in cc %}
|
||||
<div class="form-group">
|
||||
@ -68,6 +68,11 @@
|
||||
<option value="False" {% if book['custom_column_' ~ c.id]|length > 0 %}{% if book['custom_column_' ~ c.id][0].value ==false %}selected{% endif %}{% endif %}>{{_('No')}}</option>
|
||||
</select>
|
||||
{% endif %}
|
||||
|
||||
{% if c.datatype == 'int' %}
|
||||
<input type="number" step="1" class="form-control" name="{{ 'custom_column_' ~ c.id }}" id="{{ 'custom_column_' ~ c.id }}" value="{% if book['custom_column_' ~ c.id]|length > 0 %}{{ book['custom_column_' ~ c.id][0].value }}{% endif %}">
|
||||
{% endif %}
|
||||
|
||||
{% if c.datatype in ['text', 'series'] and not c.is_multiple %}
|
||||
<input type="text" class="form-control" name="{{ 'custom_column_' ~ c.id }}" id="{{ 'custom_column_' ~ c.id }}"
|
||||
{% if book['custom_column_' ~ c.id]|length > 0 %}
|
||||
@ -80,12 +85,12 @@
|
||||
{% if book['custom_column_' ~ c.id]|length > 0 %}
|
||||
value="{% for column in book['custom_column_' ~ c.id] %}{{ column.value.strip() }}{% if not loop.last %}, {% endif %}{% endfor %}"{% endif %}>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if c.datatype == 'enumeration' %}
|
||||
<select class="form-control" name="{{ 'custom_column_' ~ c.id }}" id="{{ 'custom_column_' ~ c.id }}">
|
||||
<option></option>
|
||||
{% for opt in c.get_display_dict().enum_values %}
|
||||
<option
|
||||
<option
|
||||
{% if book['custom_column_' ~ c.id]|length > 0 %}
|
||||
{% if book['custom_column_' ~ c.id][0].value == opt %}selected="selected"{% endif %}
|
||||
{% endif %}
|
||||
@ -102,9 +107,9 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input name="detail_view" type="checkbox" checked> {{_('view book after edit')}}
|
||||
|
@ -48,7 +48,7 @@ See https://github.com/adobe-type-tools/cmap-resources
|
||||
<!--<script src="pdf.js"></script>-->
|
||||
|
||||
<script type="text/javascript">
|
||||
var DEFAULT_URL = "{{ url_for('static', filename=pdffile) }}";
|
||||
var DEFAULT_URL = "{{ url_for('serve_book', book_id=pdffile,book_format='pdf') }}";
|
||||
var PDFWORKER_LOCATION="{{ url_for('static', filename='js/libs/pdf.worker.js') }}";
|
||||
// var IMAGE_LOCATION="{{ url_for('static', filename='css/../images') }}";
|
||||
var IMAGE_LOCATION="{{ url_for('static', filename='/images/') }}";
|
||||
|
@ -109,7 +109,7 @@
|
||||
$("#area").width($("#area").width());
|
||||
$("#content").width($("#content").width());
|
||||
//bind text
|
||||
$("#content").load("{{ url_for('static', filename=txtfile) }}",function(textStr) {
|
||||
$("#content").load("{{ url_for('serve_book', book_id=txtfile,book_format='txt') }}",function(textStr) {
|
||||
$(this).height($(this).parent().height()*0.95);
|
||||
$(this).text(textStr);
|
||||
});
|
||||
|
BIN
cps/translations/nl/LC_MESSAGES/messages.mo
Normal file
BIN
cps/translations/nl/LC_MESSAGES/messages.mo
Normal file
Binary file not shown.
31998
cps/translations/nl/LC_MESSAGES/messages.po
Normal file
31998
cps/translations/nl/LC_MESSAGES/messages.po
Normal file
File diff suppressed because it is too large
Load Diff
80
cps/web.py
80
cps/web.py
@ -1261,13 +1261,16 @@ def stats():
|
||||
kindlegen = os.path.join(vendorpath, u"kindlegen")
|
||||
versions['KindlegenVersion'] = _('not installed')
|
||||
if os.path.exists(kindlegen):
|
||||
p = subprocess.Popen(kindlegen, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
p.wait()
|
||||
for lines in p.stdout.readlines():
|
||||
if isinstance(lines, bytes):
|
||||
lines = lines.decode('utf-8')
|
||||
if re.search('Amazon kindlegen\(', lines):
|
||||
versions['KindlegenVersion'] = lines
|
||||
try:
|
||||
p = subprocess.Popen(kindlegen, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
p.wait()
|
||||
for lines in p.stdout.readlines():
|
||||
if isinstance(lines, bytes):
|
||||
lines = lines.decode('utf-8')
|
||||
if re.search('Amazon kindlegen\(', lines):
|
||||
versions['KindlegenVersion'] = lines
|
||||
except:
|
||||
versions['KindlegenVersion'] = _('Excecution permissions missing')
|
||||
versions['PythonVersion'] = sys.version
|
||||
versions['babel'] = babelVersion
|
||||
versions['sqlalchemy'] = sqlalchemyVersion
|
||||
@ -1290,6 +1293,12 @@ def delete_book(book_id):
|
||||
if current_user.role_delete_books():
|
||||
book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
|
||||
if book:
|
||||
# delete book from Shelfs, Downloads, Read list
|
||||
ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book_id).delete()
|
||||
ub.session.query(ub.ReadBook).filter(ub.ReadBook.book_id == book_id).delete()
|
||||
ub.session.query(ub.Downloads).filter(ub.Downloads.book_id == book_id).delete()
|
||||
ub.session.commit()
|
||||
|
||||
if config.config_use_google_drive:
|
||||
helper.delete_book_gdrive(book) # ToDo really delete file
|
||||
else:
|
||||
@ -1307,7 +1316,7 @@ def delete_book(book_id):
|
||||
cc_string = "custom_column_" + str(c.id)
|
||||
if not c.is_multiple:
|
||||
if len(getattr(book, cc_string)) > 0:
|
||||
if c.datatype == 'bool':
|
||||
if c.datatype == 'bool' or c.datatype == 'integer':
|
||||
del_cc = getattr(book, cc_string)[0]
|
||||
getattr(book, cc_string).remove(del_cc)
|
||||
db.session.delete(del_cc)
|
||||
@ -1575,6 +1584,24 @@ def get_cover(cover_path):
|
||||
else:
|
||||
return send_from_directory(os.path.join(config.config_calibre_dir, cover_path), "cover.jpg")
|
||||
|
||||
@app.route("/show/<book_id>/<book_format>")
|
||||
@login_required_if_no_ano
|
||||
def serve_book(book_id,book_format):
|
||||
book_format = book_format.split(".")[0]
|
||||
book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
|
||||
data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == book_format.upper()).first()
|
||||
app.logger.info(data.name)
|
||||
if config.config_use_google_drive:
|
||||
headers = Headers()
|
||||
try:
|
||||
headers["Content-Type"] = mimetypes.types_map['.' + book_format]
|
||||
except KeyError:
|
||||
headers["Content-Type"] = "application/octet-stream"
|
||||
df = gdriveutils.getFileFromEbooksFolder(Gdrive.Instance().drive, book.path, data.name + "." + book_format)
|
||||
return do_gdrive_download(df, headers)
|
||||
else:
|
||||
return send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + book_format)
|
||||
|
||||
|
||||
@app.route("/opds/thumb_240_240/<path:book_id>")
|
||||
@app.route("/opds/cover_240_240/<path:book_id>")
|
||||
@ -1674,19 +1701,9 @@ def read_book(book_id, book_format):
|
||||
zfile.close()
|
||||
return render_title_template('read.html', bookid=book_id, title=_(u"Read a Book"))
|
||||
elif book_format.lower() == "pdf":
|
||||
all_name = str(book_id) + "/" + book.data[0].name + ".pdf"
|
||||
tmp_file = os.path.join(book_dir, book.data[0].name) + ".pdf"
|
||||
if not os.path.exists(tmp_file):
|
||||
pdf_file = os.path.join(config.config_calibre_dir, book.path, book.data[0].name) + ".pdf"
|
||||
copyfile(pdf_file, tmp_file)
|
||||
return render_title_template('readpdf.html', pdffile=all_name, title=_(u"Read a Book"))
|
||||
return render_title_template('readpdf.html', pdffile=book_id, title=_(u"Read a Book"))
|
||||
elif book_format.lower() == "txt":
|
||||
all_name = str(book_id) + "/" + book.data[0].name + ".txt"
|
||||
tmp_file = os.path.join(book_dir, book.data[0].name) + ".txt"
|
||||
if not os.path.exists(all_name):
|
||||
txt_file = os.path.join(config.config_calibre_dir, book.path, book.data[0].name) + ".txt"
|
||||
copyfile(txt_file, tmp_file)
|
||||
return render_title_template('readtxt.html', txtfile=all_name, title=_(u"Read a Book"))
|
||||
return render_title_template('readtxt.html', txtfile=book_id, title=_(u"Read a Book"))
|
||||
elif book_format.lower() == "cbr":
|
||||
all_name = str(book_id) + "/" + book.data[0].name + ".cbr"
|
||||
tmp_file = os.path.join(book_dir, book.data[0].name) + ".cbr"
|
||||
@ -1789,10 +1806,10 @@ def login():
|
||||
if user and check_password_hash(user.password, form['password']):
|
||||
login_user(user, remember=True)
|
||||
flash(_(u"you are now logged in as: '%(nickname)s'", nickname=user.nickname), category="success")
|
||||
# test=
|
||||
return redirect(url_for("index"))
|
||||
else:
|
||||
app.logger.info('Login failed for user "'+form['username']+'"')
|
||||
ipAdress=request.headers.get('X-Forwarded-For', request.remote_addr)
|
||||
app.logger.info('Login failed for user "' + form['username'] + '" IP-adress: ' + ipAdress)
|
||||
flash(_(u"Wrong Username or Password"), category="error")
|
||||
|
||||
return render_title_template('login.html', title=_(u"login"))
|
||||
@ -2345,7 +2362,8 @@ def edit_user(user_id):
|
||||
if request.method == "POST":
|
||||
to_save = request.form.to_dict()
|
||||
if "delete" in to_save:
|
||||
ub.session.delete(content)
|
||||
ub.session.query(ub.User).filter(ub.User.id == content.id).delete()
|
||||
ub.session.commit()
|
||||
flash(_(u"User '%(nick)s' deleted", nick=content.nickname), category="success")
|
||||
return redirect(url_for('admin'))
|
||||
else:
|
||||
@ -2583,6 +2601,22 @@ def edit_book(book_id):
|
||||
cc_class = db.cc_classes[c.id]
|
||||
new_cc = cc_class(value=to_save[cc_string], book=book_id)
|
||||
db.session.add(new_cc)
|
||||
elif c.datatype == 'int':
|
||||
if to_save[cc_string] == 'None':
|
||||
to_save[cc_string] = None
|
||||
if to_save[cc_string] != cc_db_value:
|
||||
if cc_db_value is not None:
|
||||
if to_save[cc_string] is not None:
|
||||
setattr(getattr(book, cc_string)[0], 'value', to_save[cc_string])
|
||||
else:
|
||||
del_cc = getattr(book, cc_string)[0]
|
||||
getattr(book, cc_string).remove(del_cc)
|
||||
db.session.delete(del_cc)
|
||||
else:
|
||||
cc_class = db.cc_classes[c.id]
|
||||
new_cc = cc_class(value=to_save[cc_string], book=book_id)
|
||||
db.session.add(new_cc)
|
||||
|
||||
else:
|
||||
if c.datatype == 'rating':
|
||||
to_save[cc_string] = str(int(float(to_save[cc_string]) * 2))
|
||||
|
191
messages.pot
191
messages.pot
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2017-05-01 16:20+0200\n"
|
||||
"POT-Creation-Date: 2017-06-24 12:58+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -21,31 +21,46 @@ msgstr ""
|
||||
msgid "not installed"
|
||||
msgstr ""
|
||||
|
||||
#: cps/helper.py:165
|
||||
#: cps/helper.py:77
|
||||
#, python-format
|
||||
msgid "kindlegen binary %(kindlepath)s not found"
|
||||
msgstr ""
|
||||
|
||||
#: cps/helper.py:83
|
||||
#, python-format
|
||||
msgid "epub format not found for book id: %(book)d"
|
||||
msgstr ""
|
||||
|
||||
#: cps/helper.py:93
|
||||
msgid "kindlegen failed, no excecution permissions"
|
||||
msgstr ""
|
||||
|
||||
#: cps/helper.py:109
|
||||
#, python-format
|
||||
msgid "Kindlegen failed with Error %(error)s. Message: %(message)s"
|
||||
msgstr ""
|
||||
|
||||
#: cps/helper.py:186
|
||||
#, python-format
|
||||
msgid "Failed to send mail: %s"
|
||||
msgstr ""
|
||||
|
||||
#: cps/helper.py:172
|
||||
#: cps/helper.py:193
|
||||
msgid "Calibre-web test email"
|
||||
msgstr ""
|
||||
|
||||
#: cps/helper.py:173 cps/helper.py:185
|
||||
#: cps/helper.py:194 cps/helper.py:206
|
||||
msgid "This email has been sent via calibre web."
|
||||
msgstr ""
|
||||
|
||||
#: cps/helper.py:182 cps/templates/detail.html:146
|
||||
#: cps/helper.py:203 cps/templates/detail.html:146
|
||||
msgid "Send to Kindle"
|
||||
msgstr ""
|
||||
|
||||
#: cps/helper.py:202 cps/helper.py:217
|
||||
#: cps/helper.py:223 cps/helper.py:236
|
||||
msgid "Could not find any formats suitable for sending by email"
|
||||
msgstr ""
|
||||
|
||||
#: cps/helper.py:211
|
||||
msgid "Could not convert epub to mobi"
|
||||
msgstr ""
|
||||
|
||||
#: cps/ub.py:487
|
||||
msgid "Guest"
|
||||
msgstr ""
|
||||
@ -103,8 +118,8 @@ msgstr ""
|
||||
msgid "Author: %(name)s"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1078 cps/web.py:1106 cps/web.py:1239 cps/web.py:1699
|
||||
#: cps/web.py:2638
|
||||
#: cps/web.py:1078 cps/web.py:1106 cps/web.py:1239 cps/web.py:1716
|
||||
#: cps/web.py:2672
|
||||
msgid "Error opening eBook. File does not exist or file is not accessible:"
|
||||
msgstr ""
|
||||
|
||||
@ -135,240 +150,244 @@ msgstr ""
|
||||
msgid "Category: %(name)s"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1284
|
||||
#: cps/web.py:1273
|
||||
msgid "Excecution permissions missing"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1287
|
||||
msgid "Statistics"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1442
|
||||
#: cps/web.py:1451
|
||||
msgid "Server restarted, please reload page"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1444
|
||||
#: cps/web.py:1453
|
||||
msgid "Performing shutdown of server, please close window"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1460
|
||||
#: cps/web.py:1469
|
||||
msgid "Update done"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1538 cps/web.py:1551
|
||||
#: cps/web.py:1547 cps/web.py:1560
|
||||
msgid "search"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1675 cps/web.py:1682 cps/web.py:1689 cps/web.py:1696
|
||||
#: cps/web.py:1702 cps/web.py:1704 cps/web.py:1706 cps/web.py:1713
|
||||
msgid "Read a Book"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1752 cps/web.py:2234
|
||||
#: cps/web.py:1769 cps/web.py:2251
|
||||
msgid "Please fill out all fields!"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1753 cps/web.py:1769 cps/web.py:1774 cps/web.py:1776
|
||||
#: cps/web.py:1770 cps/web.py:1786 cps/web.py:1791 cps/web.py:1793
|
||||
msgid "register"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1768
|
||||
#: cps/web.py:1785
|
||||
msgid "An unknown error occured. Please try again later."
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1773
|
||||
#: cps/web.py:1790
|
||||
msgid "This username or email address is already in use."
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1791
|
||||
#: cps/web.py:1808
|
||||
#, python-format
|
||||
msgid "you are now logged in as: '%(nickname)s'"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1796
|
||||
#: cps/web.py:1813
|
||||
msgid "Wrong Username or Password"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1798
|
||||
#: cps/web.py:1815
|
||||
msgid "login"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1815
|
||||
#: cps/web.py:1832
|
||||
msgid "Please configure the SMTP mail settings first..."
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1819
|
||||
#: cps/web.py:1836
|
||||
#, python-format
|
||||
msgid "Book successfully send to %(kindlemail)s"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1823
|
||||
#: cps/web.py:1840
|
||||
#, python-format
|
||||
msgid "There was an error sending this book: %(res)s"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1825 cps/web.py:2318
|
||||
#: cps/web.py:1842 cps/web.py:2335
|
||||
msgid "Please configure your kindle email address first..."
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1850
|
||||
#: cps/web.py:1867
|
||||
#, python-format
|
||||
msgid "Book has been added to shelf: %(sname)s"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1870
|
||||
#: cps/web.py:1887
|
||||
#, python-format
|
||||
msgid "Book has been removed from shelf: %(sname)s"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1888 cps/web.py:1912
|
||||
#: cps/web.py:1905 cps/web.py:1929
|
||||
#, python-format
|
||||
msgid "A shelf with the name '%(title)s' already exists."
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1893
|
||||
#: cps/web.py:1910
|
||||
#, python-format
|
||||
msgid "Shelf %(title)s created"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1895 cps/web.py:1923
|
||||
#: cps/web.py:1912 cps/web.py:1940
|
||||
msgid "There was an error"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1896 cps/web.py:1898
|
||||
#: cps/web.py:1913 cps/web.py:1915
|
||||
msgid "create a shelf"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1921
|
||||
#: cps/web.py:1938
|
||||
#, python-format
|
||||
msgid "Shelf %(title)s changed"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1924 cps/web.py:1926
|
||||
#: cps/web.py:1941 cps/web.py:1943
|
||||
msgid "Edit a shelf"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1946
|
||||
#: cps/web.py:1963
|
||||
#, python-format
|
||||
msgid "successfully deleted shelf %(name)s"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1968
|
||||
#: cps/web.py:1985
|
||||
#, python-format
|
||||
msgid "Shelf: '%(name)s'"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:1999
|
||||
#: cps/web.py:2016
|
||||
#, python-format
|
||||
msgid "Change order of Shelf: '%(name)s'"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2063
|
||||
#: cps/web.py:2080
|
||||
msgid "Found an existing account for this email address."
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2065 cps/web.py:2069
|
||||
#: cps/web.py:2082 cps/web.py:2086
|
||||
#, python-format
|
||||
msgid "%(name)s's profile"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2066
|
||||
#: cps/web.py:2083
|
||||
msgid "Profile updated"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2080
|
||||
#: cps/web.py:2097
|
||||
msgid "Admin page"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2188
|
||||
#: cps/web.py:2205
|
||||
msgid "Calibre-web configuration updated"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2195 cps/web.py:2201 cps/web.py:2215
|
||||
#: cps/web.py:2212 cps/web.py:2218 cps/web.py:2232
|
||||
msgid "Basic Configuration"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2199
|
||||
#: cps/web.py:2216
|
||||
msgid "DB location is not valid, please enter correct path"
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/admin.html:34 cps/web.py:2236 cps/web.py:2288
|
||||
#: cps/templates/admin.html:34 cps/web.py:2253 cps/web.py:2305
|
||||
msgid "Add new user"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2280
|
||||
#: cps/web.py:2297
|
||||
#, python-format
|
||||
msgid "User '%(user)s' created"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2284
|
||||
#: cps/web.py:2301
|
||||
msgid "Found an existing account for this email address or nickname."
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2306
|
||||
#: cps/web.py:2323
|
||||
msgid "Mail settings updated"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2313
|
||||
#: cps/web.py:2330
|
||||
#, python-format
|
||||
msgid "Test E-Mail successfully send to %(kindlemail)s"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2316
|
||||
#: cps/web.py:2333
|
||||
#, python-format
|
||||
msgid "There was an error sending the Test E-Mail: %(res)s"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2320
|
||||
#: cps/web.py:2337
|
||||
msgid "E-Mail settings updated"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2321
|
||||
#: cps/web.py:2338
|
||||
msgid "Edit mail settings"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2349
|
||||
#: cps/web.py:2367
|
||||
#, python-format
|
||||
msgid "User '%(nick)s' deleted"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2445
|
||||
#: cps/web.py:2463
|
||||
#, python-format
|
||||
msgid "User '%(nick)s' updated"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2448
|
||||
#: cps/web.py:2466
|
||||
msgid "An unknown error occured."
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2451
|
||||
#: cps/web.py:2469
|
||||
#, python-format
|
||||
msgid "Edit User %(nick)s"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2486 cps/web.py:2490
|
||||
#: cps/web.py:2504 cps/web.py:2508
|
||||
msgid "unknown"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2633 cps/web.py:2636 cps/web.py:2746
|
||||
#: cps/web.py:2667 cps/web.py:2670 cps/web.py:2780
|
||||
msgid "edit metadata"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2657
|
||||
#: cps/web.py:2691
|
||||
#, python-format
|
||||
msgid "File extension \"%s\" is not allowed to be uploaded to this server"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2663
|
||||
#: cps/web.py:2697
|
||||
msgid "File to be uploaded must have an extension"
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2680
|
||||
#: cps/web.py:2714
|
||||
#, python-format
|
||||
msgid "Failed to create path %s (Permission denied)."
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2685
|
||||
#: cps/web.py:2719
|
||||
#, python-format
|
||||
msgid "Failed to store file %s (Permission denied)."
|
||||
msgstr ""
|
||||
|
||||
#: cps/web.py:2690
|
||||
#: cps/web.py:2724
|
||||
#, python-format
|
||||
msgid "Failed to delete file %s (Permission denied)."
|
||||
msgstr ""
|
||||
@ -519,7 +538,7 @@ msgid "Ok"
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/admin.html:103 cps/templates/admin.html:117
|
||||
#: cps/templates/book_edit.html:115 cps/templates/book_edit.html:137
|
||||
#: cps/templates/book_edit.html:120 cps/templates/book_edit.html:142
|
||||
#: cps/templates/config_edit.html:127 cps/templates/email_edit.html:36
|
||||
#: cps/templates/shelf.html:53 cps/templates/shelf_edit.html:19
|
||||
#: cps/templates/shelf_order.html:12 cps/templates/user_edit.html:128
|
||||
@ -542,12 +561,12 @@ msgstr ""
|
||||
msgid "Book Title"
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:26 cps/templates/book_edit.html:176
|
||||
#: cps/templates/book_edit.html:26 cps/templates/book_edit.html:181
|
||||
#: cps/templates/search_form.html:10
|
||||
msgid "Author"
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:30 cps/templates/book_edit.html:178
|
||||
#: cps/templates/book_edit.html:30 cps/templates/book_edit.html:183
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
@ -584,74 +603,74 @@ msgstr ""
|
||||
msgid "No"
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:110
|
||||
#: cps/templates/book_edit.html:115
|
||||
msgid "view book after edit"
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:113 cps/templates/book_edit.html:149
|
||||
#: cps/templates/book_edit.html:118 cps/templates/book_edit.html:154
|
||||
msgid "Get metadata"
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:114 cps/templates/config_edit.html:125
|
||||
#: cps/templates/book_edit.html:119 cps/templates/config_edit.html:125
|
||||
#: cps/templates/login.html:19 cps/templates/search_form.html:79
|
||||
#: cps/templates/shelf_edit.html:17 cps/templates/user_edit.html:126
|
||||
msgid "Submit"
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:128
|
||||
#: cps/templates/book_edit.html:133
|
||||
msgid "Are really you sure?"
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:131
|
||||
#: cps/templates/book_edit.html:136
|
||||
msgid "Book will be deleted from Calibre database"
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:132
|
||||
#: cps/templates/book_edit.html:137
|
||||
msgid "and from hard disk"
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:136
|
||||
#: cps/templates/book_edit.html:141
|
||||
msgid "Delete"
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:152
|
||||
#: cps/templates/book_edit.html:157
|
||||
msgid "Keyword"
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:153
|
||||
#: cps/templates/book_edit.html:158
|
||||
msgid " Search keyword "
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:155 cps/templates/layout.html:60
|
||||
#: cps/templates/book_edit.html:160 cps/templates/layout.html:60
|
||||
msgid "Go!"
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:156
|
||||
#: cps/templates/book_edit.html:161
|
||||
msgid "Click the cover to load metadata to the form"
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:160 cps/templates/book_edit.html:173
|
||||
#: cps/templates/book_edit.html:165 cps/templates/book_edit.html:178
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:163
|
||||
#: cps/templates/book_edit.html:168
|
||||
msgid "Close"
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:174
|
||||
#: cps/templates/book_edit.html:179
|
||||
msgid "Search error!"
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:175
|
||||
#: cps/templates/book_edit.html:180
|
||||
msgid "No Result! Please try anonther keyword."
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:177 cps/templates/detail.html:76
|
||||
#: cps/templates/book_edit.html:182 cps/templates/detail.html:76
|
||||
#: cps/templates/search_form.html:14
|
||||
msgid "Publisher"
|
||||
msgstr ""
|
||||
|
||||
#: cps/templates/book_edit.html:179
|
||||
#: cps/templates/book_edit.html:184
|
||||
msgid "Source"
|
||||
msgstr ""
|
||||
|
||||
|
@ -12,7 +12,7 @@ Calibre Web is a web app providing a clean interface for browsing, reading and d
|
||||
- full graphical setup
|
||||
- User management
|
||||
- Admin interface
|
||||
- User Interface in english, french, german, polish, russian, simplified chinese, spanish
|
||||
- User Interface in dutch, english, french, german, polish, russian, simplified chinese, spanish
|
||||
- OPDS feed for eBook reader apps
|
||||
- Filter and search by titles, authors, tags, series and language
|
||||
- Create custom book collection (shelves)
|
||||
|
Loading…
Reference in New Issue
Block a user