1
0
mirror of https://github.com/janeczku/calibre-web.git synced 2024-11-30 09:07:17 +02:00

Added polish in readme to supported UI languages

Handling of missing tags in fb import
naming of path is more imitating calibre (replacement of special characters, "pinyining" of author names if unidecode is available )
Sorting of authors (similar to calibre for jr./sr./I..IV endings)
bugfix pathseparator on windows and linux during upload
bugfix os.rename for authordir
publishing date on detailview is formated according to slected locale
filename on downloading from web ui is now correct displayed
added ids to html for testing
This commit is contained in:
OzzieIsaacs 2017-02-15 18:09:17 +01:00
parent 13caa54aad
commit 93b19165cf
18 changed files with 141 additions and 138 deletions

View File

@ -99,7 +99,7 @@ def pdf_preview(tmp_file_path, tmp_dir):
return None
else:
cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.jpg"
with Image(filename=tmp_file_path +"[0]", resolution=150) as img:
with Image(filename=tmp_file_path + "[0]", resolution=150) as img:
img.compression_quality = 88
img.save(filename=os.path.join(tmp_dir, cover_file_name))
return cover_file_name

View File

@ -227,7 +227,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): # ToDO check Authors and tags necessary
authors, tags):
self.title = title
self.sort = sort
self.author_sort = author_sort

View File

@ -6,7 +6,7 @@ import os
import uploader
import StringIO
# ToDo: Check usage of original_file_name
def get_fb2_info(tmp_file_path, original_file_extension):
ns = {
@ -20,37 +20,35 @@ def get_fb2_info(tmp_file_path, original_file_extension):
authors = tree.xpath('/fb:FictionBook/fb:description/fb:title-info/fb:author', namespaces=ns)
def get_author(element):
last_name=element.xpath('fb:last-name/text()', namespaces=ns)
last_name = element.xpath('fb:last-name/text()', namespaces=ns)
if len(last_name):
last_name=last_name[0]
last_name = last_name[0]
else:
last_name=u''
middle_name=element.xpath('fb:middle-name/text()', namespaces=ns)
last_name = u''
middle_name = element.xpath('fb:middle-name/text()', namespaces=ns)
if len(middle_name):
middle_name=middle_name[0]
middle_name = middle_name[0]
else:
middle_name=u''
first_name=element.xpath('fb:first-name/text()', namespaces=ns)
middle_name = u''
first_name = element.xpath('fb:first-name/text()', namespaces=ns)
if len(first_name):
first_name=first_name[0]
first_name = first_name[0]
else:
first_name=u''
first_name = u''
return first_name + ' ' + middle_name + ' ' + last_name
author = unicode(", ".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 = unicode(title[0])
else:
title=u''
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 = unicode(description[0])
else:
description=u''
description = u''
return uploader.BookMeta(
file_path=tmp_file_path,

View File

@ -22,6 +22,11 @@ from email.generator import Generator
from flask_babel import gettext as _
import subprocess
import shutil
try:
import unidecode
use_unidecode=True
except:
use_unidecode=False
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 ==
@ -203,7 +208,7 @@ def get_attachment(file_path):
return attachment
except IOError:
traceback.print_exc()
message = (_('The requested file could not be read. Maybe wrong permissions?')) # ToDo: What is this?
app.logger.error = (u'The requested file could not be read. Maybe wrong permissions?')
return None
@ -212,47 +217,54 @@ def get_valid_filename(value, replace_whitespace=True):
Returns the given string converted to a string that can be used for a clean
filename. Limits num characters to 128 max.
"""
value = value[:128]
# re_slugify = re.compile('[^\w\s-]', re.UNICODE)
if value[-1:] ==u'.':
value = value[:-1]+u'_'
if use_unidecode:
value=(unidecode.unidecode(value)).strip()
else:
value=value.replace('§','SS')
value=value.replace('ß','ss')
value = unicodedata.normalize('NFKD', value)
re_slugify = re.compile('[^\w\s-]', re.UNICODE)
re_slugify = re.compile('[\W\s-]', re.UNICODE)
value = unicode(re_slugify.sub('', value).strip())
if replace_whitespace:
value = re.sub('[\s]+', '_', value, flags=re.U)
value = value.replace(u"\u00DF", "ss")
#*+:\"/<>? werden durch _ ersetzt
value = re.sub('[\*\+:\\\"/<>\?]+', '_', value, flags=re.U)
value = value[:128]
return value
def get_normalized_author(value):
"""
Normalizes sorted author name
"""
value = unicodedata.normalize('NFKD', value)
value = re.sub('[^\w,\s]', '', value, flags=re.U)
value = " ".join(value.split(", ")[::-1])
return value
def get_sorted_author(value):
regexes = ["^(JR|SR)\.?$","^I{1,3}\.?$","^IV\.?$"]
combined = "(" + ")|(".join(regexes) + ")"
value = value.split(" ")
if re.match(combined,value[-1].upper()):
value2 = value[-2] + ", " + " ".join(value[:-2]) + " " + value[-1]
else:
value2 = value[-1] + ", " + " ".join(value[:-1])
return value2
def update_dir_stucture(book_id, calibrepath):
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()
path = os.path.join(calibrepath, book.path)
path = os.path.join(calibrepath, book.path)#.replace('/',os.path.sep)).replace('\\',os.path.sep)
authordir = book.path.split(os.sep)[0]
new_authordir = get_valid_filename(book.authors[0].name, False)
titledir = book.path.split(os.sep)[1]
new_titledir = get_valid_filename(book.title, False) + " (" + str(book_id) + ")"
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:
new_title_path = os.path.join(os.path.dirname(path), new_titledir)
os.rename(path, new_title_path)
path = new_title_path
book.path = book.path.split(os.sep)[0] + os.sep + new_titledir
book.path = book.path.split('/')[0] + '/' + new_titledir
if authordir != new_authordir:
new_author_path = os.path.join(os.path.join(calibrepath, new_authordir), os.path.basename(path))
os.renames(path, new_author_path)
book.path = new_authordir + os.sep + book.path.split(os.sep)[1]
os.rename(path, new_author_path)
book.path = new_authordir + '/' + book.path.split('/')[1]
db.session.commit()

View File

@ -2,7 +2,7 @@
{% block body %}
<div class="discover">
<h2>{{_('User list')}}</h2>
<table class="table table-striped">
<table class="table table-striped" id="table_user">
<tr>
<th>{{_('Nickname')}}</th>
<th>{{_('Email')}}</th>
@ -30,9 +30,9 @@
{% endif %}
{% endfor %}
</table>
<div class="btn btn-default"><a href="{{url_for('new_user')}}">{{_('Add new user')}}</a></div>
<div class="btn btn-default" id="admin_new_user"><a href="{{url_for('new_user')}}">{{_('Add new user')}}</a></div>
<h2>{{_('SMTP mail settings')}}</h2>
<table class="table table-striped">
<table class="table table-striped" id="table_email">
<tr>
<th>{{_('SMTP hostname')}}</th>
<th>{{_('SMTP port')}}</th>
@ -51,10 +51,10 @@
</table>
<div class="btn btn-default"><a href="{{url_for('edit_mailsettings')}}">{{_('Change SMTP settings')}}</a></div>
<div class="btn btn-default" id="admin_edit_email"><a href="{{url_for('edit_mailsettings')}}">{{_('Change SMTP settings')}}</a></div>
<h2>{{_('Configuration')}}</h2>
<table class="table table-striped">
<table class="table table-striped" id="table_configuration">
<tr>
<th>{{_('Calibre DB dir')}}</th>
<th>{{_('Log Level')}}</th>
@ -76,6 +76,7 @@
<div class="btn btn-default"><a href="{{url_for('configuration')}}">{{_('Configuration')}}</a></div>
<h2>{{_('Administration')}}</h2>
{% if not development %}
<p>{{_('Current commit timestamp')}}: {{commit}} </p>
<div class="btn btn-default" data-toggle="modal" data-target="#RestartDialog">{{_('Restart Calibre-web')}}</a></div>
<div class="btn btn-default" data-toggle="modal" data-target="#ShutdownDialog">{{_('Stop Calibre-web')}}</a></div>
<div class="btn btn-default" id="check_for_update">{{_('Check for update')}}</a></div>

View File

@ -70,8 +70,8 @@
</div>
</p>
{% endif %}
{% if entry.pubdate != '0101-01-01 00:00:00' %}
<p>{{_('Publishing date')}}: {{entry.pubdate[:10]}} </p>
{% if entry.pubdate[:10] != '0101-01-01' %}
<p>{{_('Publishing date')}}: {{entry.pubdate|formatdate}} </p>
{% endif %}
{% if cc|length > 0 %}
<p>

View File

@ -6,7 +6,7 @@
<div class="row">
{% for entry in random %}
<div class="col-sm-3 col-lg-2 col-xs-6 book">
<div id="books_rand" class="col-sm-3 col-lg-2 col-xs-6 book">
<div class="cover">
<a href="{{ url_for('show_book', id=entry.id) }}">
{% if entry.has_cover %}
@ -41,7 +41,7 @@
<h2>{{title}}</h2>
<div class="row">
{% for entry in entries %}
<div class="col-sm-3 col-lg-2 col-xs-6 book">
<div id="books" class="col-sm-3 col-lg-2 col-xs-6 book">
<div class="cover">
<a href="{{ url_for('show_book', id=entry.id) }}">
{% if entry.has_cover %}

View File

@ -5,7 +5,7 @@
{% for lang in languages %}
<div class="row">
<div class="col-xs-1" align="left"><span class="badge">{{lang_counter[loop.index0].bookcount}}</span></div>
<div class="col-xs-6"><a href="{{url_for('language', name=lang.lang_code)}}">{{lang.name}}</a></div>
<div class="col-xs-6"><a id="list_{{loop.index0}}" href="{{url_for('language', name=lang.lang_code)}}">{{lang.name}}</a></div>
</div>
{% endfor %}
</div>

View File

@ -80,16 +80,16 @@
{% endif %}
{% endif %}
{% if g.user.role_admin() %}
<li><a href="{{url_for('admin')}}"><span class="glyphicon glyphicon-dashboard"></span> {{_('Admin')}}</a></li>
<li><a id="top_admin" href="{{url_for('admin')}}"><span class="glyphicon glyphicon-dashboard"></span> {{_('Admin')}}</a></li>
{% endif %}
<li><a href="{{url_for('profile')}}"><span class="glyphicon glyphicon-user"></span> {{g.user.nickname}}</a></li>
<li><a id="top_user" href="{{url_for('profile')}}"><span class="glyphicon glyphicon-user"></span> {{g.user.nickname}}</a></li>
{% if not g.user.is_anonymous() %}
<li><a href="{{url_for('logout')}}"><span class="glyphicon glyphicon-log-out"></span> {{_('Logout')}}</a></li>
<li><a id="logout" href="{{url_for('logout')}}"><span class="glyphicon glyphicon-log-out"></span> {{_('Logout')}}</a></li>
{% endif %}
{% endif %}
{% if g.allow_registration and not g.user.is_authenticated %}
<li><a href="{{url_for('login')}}"><span class="glyphicon glyphicon-log-in"></span> {{_('Login')}}</a></li>
<li><a href="{{url_for('register')}}"><span class="glyphicon glyphicon-user"></span> {{_('Register')}}</a></li>
<li><a id="login" href="{{url_for('login')}}"><span class="glyphicon glyphicon-log-in"></span> {{_('Login')}}</a></li>
<li><a id="register" href="{{url_for('register')}}"><span class="glyphicon glyphicon-user"></span> {{_('Register')}}</a></li>
{% endif %}
</ul>
</div><!--/.nav-collapse -->
@ -98,17 +98,17 @@
{% for message in get_flashed_messages(with_categories=True) %}
{%if message[0] == "error" %}
<div class="row-fluid" style="margin-top: -20px; text-align: center;">
<div class="alert alert-danger">{{ message[1] }}</div>
<div id="flash_alert" class="alert alert-danger">{{ message[1] }}</div>
</div>
{%endif%}
{%if message[0] == "info" %}
<div class="row-fluid" style="margin-top: -20px; text-align: center;">
<div class="alert alert-info">{{ message[1] }}</div>
<div id="flash_info" class="alert alert-info">{{ message[1] }}</div>
</div>
{%endif%}
{%if message[0] == "success" %}
<div class="row-fluid" style="margin-top: -20px; text-align: center;">
<div class="alert alert-success">{{ message[1] }}</div>
<div id="flash_success" class="alert alert-success">{{ message[1] }}</div>
</div>
{%endif%}
{% endfor %}
@ -119,25 +119,25 @@
<nav class="navigation">
<ul class="list-unstyled" id="scnd-nav" intent in-standard-append="nav.navigation" in-mobile-after="#main-nav" in-mobile-class="nav navbar-nav">
<li class="nav-head hidden-xs">{{_('Browse')}}</li>
<li><a href="{{url_for('index')}}"><span class="glyphicon glyphicon-book"></span> {{_('New Books')}}</a></li>
<li id="nav_new"><a href="{{url_for('index')}}"><span class="glyphicon glyphicon-book"></span> {{_('New Books')}}</a></li>
{% if g.user.show_hot_books() %}
<li><a href="{{url_for('hot_books')}}"><span class="glyphicon glyphicon-fire"></span> {{_('Hot Books')}}</a></li>
<li id="nav_hot"><a href="{{url_for('hot_books')}}"><span class="glyphicon glyphicon-fire"></span> {{_('Hot Books')}}</a></li>
{%endif%}
{% 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_random_books() %}
<li><a href="{{url_for('discover')}}"><span class="glyphicon glyphicon-random"></span> {{_('Discover')}}</a></li>
<li id="nav_rand"><a href="{{url_for('discover')}}"><span class="glyphicon glyphicon-random"></span> {{_('Discover')}}</a></li>
{%endif%}
{% if g.user.show_category() %}
<li><a href="{{url_for('category_list')}}"><span class="glyphicon glyphicon-inbox"></span> {{_('Categories')}}</a></li>
<li id="nav_cat"><a href="{{url_for('category_list')}}"><span class="glyphicon glyphicon-inbox"></span> {{_('Categories')}}</a></li>
{%endif%}
{% if g.user.show_series() %}
<li><a href="{{url_for('series_list')}}"><span class="glyphicon glyphicon-bookmark"></span> {{_('Series')}}</a></li>
<li id="nav_serie"><a href="{{url_for('series_list')}}"><span class="glyphicon glyphicon-bookmark"></span> {{_('Series')}}</a></li>
{%endif%}
<li><a href="{{url_for('author_list')}}"><span class="glyphicon glyphicon-user"></span> {{_('Authors')}}</a></li>
<li id="nav_author"><a href="{{url_for('author_list')}}"><span class="glyphicon glyphicon-user"></span> {{_('Authors')}}</a></li>
{% if g.user.filter_language() == 'all' and g.user.show_language() %}
<li><a href="{{url_for('language_overview')}}"><span class="glyphicon glyphicon-flag"></span> {{_('Languages')}} </a></li>
<li id="nav_lang"><a href="{{url_for('language_overview')}}"><span class="glyphicon glyphicon-flag"></span> {{_('Languages')}} </a></li>
{%endif%}
{% if g.user.is_authenticated or g.user.is_anonymous() %}
<li class="nav-head hidden-xs">{{_('Public Shelves')}}</li>
@ -160,9 +160,9 @@
{% endif %}
<div class="col-sm-10">
{% block body %}{% endblock %}
{% if pagination %}
{% if pagination and (pagination.has_next or pagination.has_prev) %}
<div class="pagination">
{%- for page in pagination.iter_pages() %}
{% for page in pagination.iter_pages() %}
{% if page %}
{% if page != pagination.page %}
<a href="{{ url_for_other_page(page) }}">{{ page }}</a>
@ -172,7 +172,7 @@
{% else %}
<span class="ellipsis"></span>
{% endif %}
{%- endfor %}
{% endfor %}
{% if pagination.has_next %}
<a class="next" href="{{ url_for_other_page(pagination.page + 1)
}}">Next &raquo;</a>

View File

@ -5,7 +5,7 @@
{% for entry in entries %}
<div class="row">
<div class="col-xs-1" align="left"><span class="badge">{{entry.count}}</span></div>
<div class="col-xs-6"><a href="{{url_for(folder, id=entry[0].id )}}">{{entry[0].name}}</a></div>
<div class="col-xs-6"><a id="list_{{loop.index0}}" href="{{url_for(folder, id=entry[0].id )}}">{{entry[0].name}}</a></div>
</div>
{% endfor %}
</div>

View File

@ -16,7 +16,7 @@
<input type="checkbox" name="remember_me" checked> {{_('Remember me')}}
</label>
</div>
<button type="submit" class="btn btn-default">{{_('Submit')}}</button>
<button type="submit" name="submit" class="btn btn-default">{{_('Submit')}}</button>
</form>
</div>
{% if error %}

View File

@ -2,7 +2,7 @@
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
<LongName>{{instance}}</LongName>
<ShortName>{{instance}}</ShortName>
<Description>{{_('instanceCalibre Web ebook catalog')}}</Description>
<Description>{{_('Calibre Web ebook catalog')}}</Description>
<Developer>Janeczku</Developer>
<Contact>https://github.com/janeczku/calibre-web</Contact>
<Url type="text/html"

View File

@ -2,7 +2,7 @@
{% block body %}
<h3>{{_('Linked libraries')}}</h3>
<table class="table">
<table id="libs" class="table">
<thead>
<tr>
<th>{{_('Program library')}}</th>
@ -30,7 +30,7 @@
</table>
<h3>{{_('Calibre library statistics')}}</h3>
<table class="table">
<table id="stats" class="table">
<tbody>
<tr>
<th>{{bookcounter}}</th>

View File

@ -27,7 +27,7 @@
<label for="locale">{{_('Language')}}</label>
<select name="locale" id="locale" class="form-control">
{% for translation in translations %}
<option value="{{translation}}" {% if translation.language == content.locale %}selected{% endif %} {% if new_user == 1 and loop.first %}selected{% endif %}>{{ translation.display_name }}</option>
<option value="{{translation}}" {% if translation|string == content.locale %}selected{% endif %} {% if new_user == 1 and loop.first %}selected{% endif %}>{{ translation.display_name }}</option>
{% endfor %}
</select>
</div>
@ -108,7 +108,7 @@
{% endif %}
<button type="submit" id="submit" class="btn btn-default">{{_('Submit')}}</button>
{% if not profile %}
<a href="{{ url_for('admin') }}" class="btn btn-default">{{_('Back')}}</a>
<a href="{{ url_for('admin') }}" id="back" class="btn btn-default">{{_('Back')}}</a>
{% endif %}
</form>

View File

@ -81,7 +81,7 @@ msgstr "Beliebte Bücher (die meisten Downloads)"
#: cps/web.py:813
msgid "Best rated books"
msgstr ""
msgstr "Best bewertete Bücher"
#: cps/templates/index.xml:36 cps/web.py:822
msgid "Random Books"
@ -94,7 +94,7 @@ msgstr "Autorenliste"
#: cps/web.py:846
#, python-format
msgid "Author: %(name)s"
msgstr ""
msgstr "Autor: %(name)s"
#: cps/web.py:848 cps/web.py:876 cps/web.py:975 cps/web.py:1216 cps/web.py:2103
msgid "Error opening eBook. File does not exist or file is not accessible:"
@ -143,7 +143,7 @@ msgstr "Server wird runtergefahren, bitte Fenster schließen"
#: cps/web.py:1055
msgid "Update done"
msgstr ""
msgstr "Update durchgeführt"
#: cps/web.py:1128 cps/web.py:1141
msgid "search"
@ -470,11 +470,11 @@ msgstr "Stoppe Calibre-web"
#: cps/templates/admin.html:81
msgid "Check for update"
msgstr ""
msgstr "Suche nach Update"
#: cps/templates/admin.html:82
msgid "Perform Update"
msgstr ""
msgstr "Update durchführen"
#: cps/templates/admin.html:93
msgid "Do you really want to restart Calibre-web?"
@ -584,7 +584,7 @@ msgstr "Öffentliche Registrierung aktivieren"
#: cps/templates/config_edit.html:52
msgid "Default Settings for new users"
msgstr ""
msgstr "Default Einstellungen für neue Benutzer"
#: cps/templates/config_edit.html:55 cps/templates/user_edit.html:80
msgid "Admin user"
@ -625,7 +625,7 @@ msgstr "Sprache"
#: cps/templates/detail.html:74
msgid "Publishing date"
msgstr ""
msgstr "Herausgabedatum"
#: cps/templates/detail.html:106
msgid "Description:"
@ -699,11 +699,11 @@ msgstr "Beliebte Bücher"
#: cps/templates/index.xml:19
msgid "Popular publications from this catalog based on Downloads."
msgstr ""
msgstr "Beliebte Publikationen aus dieser Bibliothek basierend auf Downloadzahlen"
#: cps/templates/index.xml:22 cps/templates/layout.html:127
msgid "Best rated Books"
msgstr ""
msgstr "Best bewertete Bücher"
#: cps/templates/index.xml:26
msgid "Popular publications from this catalog based on Rating."
@ -804,8 +804,8 @@ msgid "Remember me"
msgstr "Merken"
#: cps/templates/osd.xml:5
msgid "instanceCalibre Web ebook catalog"
msgstr ""
msgid "Calibre Web ebook catalog"
msgstr "Calibre Web Ebook Katalog"
#: cps/templates/read.html:136
msgid "Reflow text when sidebars are open."
@ -909,11 +909,11 @@ msgstr "Autoren in dieser Bibliothek"
#: cps/templates/stats.html:45
msgid "Categories in this Library"
msgstr ""
msgstr "Kategorien in dieser Bibliothek"
#: cps/templates/stats.html:49
msgid "Series in this Library"
msgstr ""
msgstr "Serien in dieser Bibliothek"
#: cps/templates/user_edit.html:23
msgid "Kindle E-Mail"
@ -937,7 +937,7 @@ msgstr "Zeige Auswahl Beliebte Bücher"
#: cps/templates/user_edit.html:53
msgid "Show best rated books"
msgstr ""
msgstr "Zeige am besten bewertete Bücher"
#: cps/templates/user_edit.html:57
msgid "Show language selection"

View File

@ -144,7 +144,6 @@ class UserBase:
else:
return False
def __repr__(self):
return '<User %r>' % self.nickname
@ -164,10 +163,6 @@ class User(UserBase, Base):
downloads = relationship('Downloads', backref='user', lazy='dynamic')
locale = Column(String(2), default="en")
sidebar_view = Column(Integer, default=1)
#language_books = Column(Integer, default=1)
#series_books = Column(Integer, default=1)
#category_books = Column(Integer, default=1)
#hot_books = Column(Integer, default=1)
default_language = Column(String(3), default="all")
@ -184,10 +179,6 @@ class Anonymous(AnonymousUserMixin, UserBase):
self.role = data.role
self.sidebar_view = data.sidebar_view
self.default_language = data.default_language
#self.language_books = data.language_books
#self.series_books = data.series_books
#self.category_books = data.category_books
#self.hot_books = data.hot_books
self.default_language = data.default_language
self.locale = data.locale
self.anon_browse = settings.config_anonbrowse

View File

@ -25,6 +25,7 @@ import zipfile
from werkzeug.security import generate_password_hash, check_password_hash
from babel import Locale as LC
from babel import negotiate_locale
from babel.dates import format_date
from functools import wraps
import base64
from sqlalchemy.sql import *
@ -279,6 +280,12 @@ def mimetype_filter(val):
s = 'application/octet-stream'
return s
@app.template_filter('formatdate')
def formatdate(val):
conformed_timestamp = re.sub(r"[:]|([-](?!((\d{2}[:]\d{2})|(\d{4}))$))", '', val)
formatdate = datetime.datetime.strptime(conformed_timestamp[:-5], "%Y%m%d %H%M%S")
return format_date(formatdate, format='medium',locale=get_locale())
def admin_required(f):
"""
@ -658,10 +665,9 @@ def get_opds_download_link(book_id, format):
data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == format.upper()).first()
if current_user.is_authenticated:
helper.update_download(book_id, int(current_user.id))
author = helper.get_normalized_author(book.author_sort)
file_name = book.title
if len(author) > 0:
file_name = author + '-' + file_name
if len(book.authors) > 0:
file_name = book.authors[0].name + '-' + file_name
file_name = helper.get_valid_filename(file_name)
response = make_response(send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + format))
response.headers["Content-Disposition"] = "attachment; filename=\"%s.%s\"" % (data.name, format)
@ -1228,10 +1234,9 @@ def get_download_link(book_id, format):
# collect downloaded books only for registered user and not for anonymous user
if current_user.is_authenticated:
helper.update_download(book_id, int(current_user.id))
author = helper.get_normalized_author(book.author_sort)
file_name = book.title
if len(author) > 0:
file_name = author + '-' + file_name
if len(book.authors) > 0:
file_name = book.authors[0].name + '-' + file_name
file_name = helper.get_valid_filename(file_name)
response = make_response(
send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + format))
@ -1239,13 +1244,7 @@ def get_download_link(book_id, format):
response.headers["Content-Type"] = mimetypes.types_map['.' + format]
except:
pass
response.headers["Content-Disposition"] = \
"attachment; " \
"filename={utf_filename}.{suffix};" \
"filename*=UTF-8''{utf_filename}.{suffix}".format(
utf_filename=file_name.encode('utf-8'),
suffix=format
)
response.headers["Content-Disposition"] = "attachment; filename=\"%s.%s\"" % (file_name.encode('utf-8'), format)
return response
else:
abort(404)
@ -1599,6 +1598,7 @@ def basic_configuration():
def configuration_helper(origin):
global global_task
commit='$Format:%cI$'
reboot_required = False
db_change = False
success = False
@ -1659,13 +1659,13 @@ def configuration_helper(origin):
logging.getLogger("book_formats").setLevel(config.config_log_level)
except e:
flash(e, category="error")
return render_title_template("config_edit.html", content=config, origin=origin,
return render_title_template("config_edit.html", content=config, origin=origin, commit=commit,
title=_(u"Basic Configuration"))
if db_change:
reload(db)
if not db.setup_db():
flash(_(u'DB location is not valid, please enter correct path'), category="error")
return render_title_template("config_edit.html", content=config, origin=origin,
return render_title_template("config_edit.html", content=config, origin=origin, commit=commit,
title=_(u"Basic Configuration"))
if reboot_required:
# db.engine.dispose() # ToDo verify correct
@ -1678,7 +1678,7 @@ def configuration_helper(origin):
app.logger.info('Reboot required, restarting')
if origin:
success = True
return render_title_template("config_edit.html", origin=origin, success=success, content=config,
return render_title_template("config_edit.html", origin=origin, success=success, content=config, commit=commit,
title=_(u"Basic Configuration"))
@ -1927,7 +1927,7 @@ def edit_book(book_id):
modify_database_object(input_authors, book.authors, db.Authors, db.session, 'author')
if author0_before_edit != book.authors[0].name:
edited_books_id.add(book.id)
book.author_sort=helper.get_normalized_author(input_authors[0]) # ToDo: wrong sorting
book.author_sort=helper.get_sorted_author(input_authors[0])
if to_save["cover_url"] and os.path.splitext(to_save["cover_url"])[1].lower() == ".jpg":
img = requests.get(to_save["cover_url"])
@ -2155,9 +2155,10 @@ def upload():
if is_author:
db_author = is_author
else:
db_author = db.Authors(author, helper.get_normalized_author(author), "") # TODO: WRONG Sorting Author function
db_author = db.Authors(author, helper.get_sorted_author(author), "")
db.session.add(db_author)
path = os.path.join(author_dir, title_dir)
# combine path and normalize path from windows systems
path = os.path.join(author_dir, title_dir).replace('\\','/')
db_book = db.Books(title, "", db_author.sort, datetime.datetime.now(), datetime.datetime(101, 01, 01), 1,
datetime.datetime.now(), path, has_cover, db_author, [])
db_book.authors.append(db_author)

View File

@ -11,7 +11,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, simplified chinese, spanish
- User Interface in english, french, german, polish, simplified chinese, spanish
- OPDS feed for eBook reader apps
- Filter and search by titles, authors, tags, series and language
- Create custom book collection (shelves)