mirror of
https://github.com/janeczku/calibre-web
synced 2024-12-25 09:30:31 +00: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:
parent
13caa54aad
commit
93b19165cf
@ -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
|
||||
|
32
cps/db.py
32
cps/db.py
@ -32,29 +32,29 @@ def title_sort(title):
|
||||
Base = declarative_base()
|
||||
|
||||
books_authors_link = Table('books_authors_link', Base.metadata,
|
||||
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
|
||||
Column('author', Integer, ForeignKey('authors.id'), primary_key=True)
|
||||
)
|
||||
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
|
||||
Column('author', Integer, ForeignKey('authors.id'), primary_key=True)
|
||||
)
|
||||
|
||||
books_tags_link = Table('books_tags_link', Base.metadata,
|
||||
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
|
||||
Column('tag', Integer, ForeignKey('tags.id'), primary_key=True)
|
||||
)
|
||||
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
|
||||
Column('tag', Integer, ForeignKey('tags.id'), primary_key=True)
|
||||
)
|
||||
|
||||
books_series_link = Table('books_series_link', Base.metadata,
|
||||
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
|
||||
Column('series', Integer, ForeignKey('series.id'), primary_key=True)
|
||||
)
|
||||
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
|
||||
Column('series', Integer, ForeignKey('series.id'), primary_key=True)
|
||||
)
|
||||
|
||||
books_ratings_link = Table('books_ratings_link', Base.metadata,
|
||||
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
|
||||
Column('rating', Integer, ForeignKey('ratings.id'), primary_key=True)
|
||||
)
|
||||
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
|
||||
Column('rating', Integer, ForeignKey('ratings.id'), primary_key=True)
|
||||
)
|
||||
|
||||
books_languages_link = Table('books_languages_link', Base.metadata,
|
||||
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
|
||||
Column('lang_code', Integer, ForeignKey('languages.id'), primary_key=True)
|
||||
)
|
||||
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
|
||||
Column('lang_code', Integer, ForeignKey('languages.id'), primary_key=True)
|
||||
)
|
||||
|
||||
|
||||
class Identifiers(Base):
|
||||
@ -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
|
||||
|
32
cps/fb2.py
32
cps/fb2.py
@ -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''
|
||||
return first_name + ' ' + middle_name + ' ' + last_name
|
||||
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,
|
||||
|
@ -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)
|
||||
value = unicodedata.normalize('NFKD', value)
|
||||
re_slugify = re.compile('[^\w\s-]', re.UNICODE)
|
||||
value = unicode(re_slugify.sub('', value).strip())
|
||||
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)
|
||||
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_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 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 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()
|
||||
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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 %}
|
||||
|
@ -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>
|
||||
|
@ -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 »</a>
|
||||
|
@ -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>
|
||||
|
@ -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 %}
|
||||
|
@ -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"
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
41
cps/web.py
41
cps/web.py
@ -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,16 +1659,16 @@ 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
|
||||
# db.engine.dispose() # ToDo verify correct
|
||||
ub.session.close()
|
||||
ub.engine.dispose()
|
||||
# stop tornado server
|
||||
@ -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)
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user