Commit f11b1236 authored by idalin's avatar idalin

merge conflicts

parents 348a7fd2 861920af
web.py ident export-subst
[General]
DB_ROOT =
APP_DB_ROOT =
MAIN_DIR =
LOG_DIR =
PORT = 8083
NEWEST_BOOKS = 60
[Advanced]
TITLE_REGEX = ^(A|The|An|Der|Die|Das|Den|Ein|Eine|Einen|Dem|Des|Einem|Eines)\s+
DEVELOPMENT = 0
PUBLIC_REG = 0
UPLOADING = 0
ANON_BROWSE = 0
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*-
import os import os
import sys import sys
from threading import Thread
from multiprocessing import Queue
import time import time
base_path = os.path.dirname(os.path.abspath(__file__)) base_path = os.path.dirname(os.path.abspath(__file__))
# Insert local directories into path # Insert local directories into path
sys.path.insert(0, os.path.join(base_path, 'vendor')) sys.path.insert(0, os.path.join(base_path, 'vendor'))
from cps import web from cps import web
from cps import config
from tornado.wsgi import WSGIContainer from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop from tornado.ioloop import IOLoop
global title_sort if __name__ == '__main__':
if web.ub.DEVELOPMENT:
web.app.run(host="0.0.0.0", port=web.ub.config.config_port, debug=True)
def start_calibreweb(messagequeue):
web.global_queue = messagequeue
if config.DEVELOPMENT:
web.app.run(host="0.0.0.0", port=config.PORT, debug=True)
else: else:
http_server = HTTPServer(WSGIContainer(web.app)) http_server = HTTPServer(WSGIContainer(web.app))
http_server.listen(config.PORT) http_server.listen(web.ub.config.config_port)
IOLoop.instance().start() IOLoop.instance().start()
print "Tornado finished"
http_server.stop()
def stop_calibreweb(): if web.global_task == 0:
# Close Database connections for user and data print("Performing restart of Calibre-web")
web.db.session.close() os.execl(sys.executable, sys.executable, *sys.argv)
web.db.engine.dispose()
web.ub.session.close()
web.ub.engine.dispose()
test=IOLoop.instance()
test.add_callback(test.stop)
print("Asked Tornado to exit")
if __name__ == '__main__':
if config.DEVELOPMENT:
web.app.run(host="0.0.0.0",port=config.PORT, debug=True)
else: else:
while True: print("Performing shutdown of Calibre-web")
q = Queue() sys.exit(0)
t = Thread(target=start_calibreweb, args=(q,))
t.start()
while True: #watching queue, if there is no call than sleep, otherwise break
if q.empty():
time.sleep(1)
else:
break
stop_calibreweb()
t.join()
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import logging import logging
import uploader import uploader
import os import os
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
from configobj import ConfigObj
CONFIG_FILE = os.path.join(os.path.normpath(os.path.dirname(os.path.realpath(__file__))+os.sep+".."+os.sep), "config.ini")
CFG = ConfigObj(CONFIG_FILE)
CFG.encoding = 'UTF-8'
def CheckSection(sec):
""" Check if INI section exists, if not create it """
try:
CFG[sec]
return True
except:
CFG[sec] = {}
return False
def check_setting_str(config, cfg_name, item_name, def_val, log=True):
try:
my_val = config[cfg_name][item_name].decode('UTF-8')
if my_val == u"":
my_val = def_val
config[cfg_name][item_name] = my_val
except:
my_val = def_val
try:
config[cfg_name][item_name] = my_val
except:
config[cfg_name] = {}
config[cfg_name][item_name] = my_val
return my_val
def check_setting_int(config, cfg_name, item_name, def_val):
try:
my_val = int(config[cfg_name][item_name])
except:
my_val = def_val
try:
config[cfg_name][item_name] = my_val
except:
config[cfg_name] = {}
config[cfg_name][item_name] = my_val
return my_val
CheckSection('General')
DB_ROOT = check_setting_str(CFG, 'General', 'DB_ROOT', "")
APP_DB_ROOT = check_setting_str(CFG, 'General', 'APP_DB_ROOT', os.getcwd())
MAIN_DIR = check_setting_str(CFG, 'General', 'MAIN_DIR', os.getcwd())
LOG_DIR = check_setting_str(CFG, 'General', 'LOG_DIR', os.getcwd())
PORT = check_setting_int(CFG, 'General', 'PORT', 8083)
NEWEST_BOOKS = check_setting_str(CFG, 'General', 'NEWEST_BOOKS', 60)
RANDOM_BOOKS = check_setting_int(CFG, 'General', 'RANDOM_BOOKS', 4)
CheckSection('Advanced')
TITLE_REGEX = check_setting_str(CFG, 'Advanced', 'TITLE_REGEX', '^(A|The|An|Der|Die|Das|Den|Ein|Eine|Einen|Dem|Des|Einem|Eines)\s+')
DEVELOPMENT = bool(check_setting_int(CFG, 'Advanced', 'DEVELOPMENT', 0))
PUBLIC_REG = bool(check_setting_int(CFG, 'Advanced', 'PUBLIC_REG', 0))
UPLOADING = bool(check_setting_int(CFG, 'Advanced', 'UPLOADING', 0))
ANON_BROWSE = bool(check_setting_int(CFG, 'Advanced', 'ANON_BROWSE', 0))
SYS_ENCODING = "UTF-8"
if DB_ROOT == "":
print "Calibre database directory (DB_ROOT) is not configured"
sys.exit(1)
configval = {"DB_ROOT": DB_ROOT, "APP_DB_ROOT": APP_DB_ROOT, "MAIN_DIR": MAIN_DIR, "LOG_DIR": LOG_DIR, "PORT": PORT,
"NEWEST_BOOKS": NEWEST_BOOKS, "DEVELOPMENT": DEVELOPMENT, "TITLE_REGEX": TITLE_REGEX,
"PUBLIC_REG": PUBLIC_REG, "UPLOADING": UPLOADING, "ANON_BROWSE": ANON_BROWSE}
def save_config(configval):
new_config = ConfigObj(encoding='UTF-8')
new_config.filename = CONFIG_FILE
new_config['General'] = {}
new_config['General']['DB_ROOT'] = configval["DB_ROOT"]
new_config['General']['APP_DB_ROOT'] = configval["APP_DB_ROOT"]
new_config['General']['MAIN_DIR'] = configval["MAIN_DIR"]
new_config['General']['LOG_DIR'] = configval["LOG_DIR"]
new_config['General']['PORT'] = configval["PORT"]
new_config['General']['NEWEST_BOOKS'] = configval["NEWEST_BOOKS"]
new_config['Advanced'] = {}
new_config['Advanced']['TITLE_REGEX'] = configval["TITLE_REGEX"]
new_config['Advanced']['DEVELOPMENT'] = int(configval["DEVELOPMENT"])
new_config['Advanced']['PUBLIC_REG'] = int(configval["PUBLIC_REG"])
new_config['Advanced']['UPLOADING'] = int(configval["UPLOADING"])
new_config['Advanced']['ANON_BROWSE'] = int(configval["ANON_BROWSE"])
new_config.write()
return "Saved"
save_config(configval)
...@@ -5,15 +5,24 @@ from sqlalchemy import * ...@@ -5,15 +5,24 @@ from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import * from sqlalchemy.orm import *
import os import os
import config
import re import re
import ast import ast
from ub import config
import ub
# calibre sort stuff session = None
title_pat = re.compile(config.TITLE_REGEX, re.IGNORECASE) cc_exceptions = None
cc_classes = None
cc_ids = None
books_custom_column_links = None
engine = None
# user defined sort function for calibre databases (Series, etc.)
def title_sort(title): def title_sort(title):
# calibre sort stuff
# config=Config()
title_pat = re.compile(config.config_title_regex, re.IGNORECASE)
match = title_pat.search(title) match = title_pat.search(title)
if match: if match:
prep = match.group(1) prep = match.group(1)
...@@ -21,59 +30,32 @@ def title_sort(title): ...@@ -21,59 +30,32 @@ def title_sort(title):
return title.strip() return title.strip()
dbpath = os.path.join(config.DB_ROOT, "metadata.db")
engine = create_engine('sqlite:///{0}'.format(dbpath.encode('utf-8')), echo=False)
conn = engine.connect()
conn.connection.create_function('title_sort', 1, title_sort)
Base = declarative_base() Base = declarative_base()
books_authors_link = Table('books_authors_link', Base.metadata, books_authors_link = Table('books_authors_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'), primary_key=True), Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('author', Integer, ForeignKey('authors.id'), primary_key=True) Column('author', Integer, ForeignKey('authors.id'), primary_key=True)
) )
books_tags_link = Table('books_tags_link', Base.metadata, books_tags_link = Table('books_tags_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'), primary_key=True), Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('tag', Integer, ForeignKey('tags.id'), primary_key=True) Column('tag', Integer, ForeignKey('tags.id'), primary_key=True)
) )
books_series_link = Table('books_series_link', Base.metadata, books_series_link = Table('books_series_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'), primary_key=True), Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('series', Integer, ForeignKey('series.id'), primary_key=True) Column('series', Integer, ForeignKey('series.id'), primary_key=True)
) )
books_ratings_link = Table('books_ratings_link', Base.metadata, books_ratings_link = Table('books_ratings_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'), primary_key=True), Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('rating', Integer, ForeignKey('ratings.id'), primary_key=True) Column('rating', Integer, ForeignKey('ratings.id'), primary_key=True)
) )
books_languages_link = Table('books_languages_link', Base.metadata, books_languages_link = Table('books_languages_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'), primary_key=True), Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('lang_code', Integer, ForeignKey('languages.id'), primary_key=True) Column('lang_code', Integer, ForeignKey('languages.id'), primary_key=True)
) )
cc = conn.execute("SELECT id, datatype FROM custom_columns")
cc_ids = []
cc_exceptions = ['datetime', 'int', 'comments', 'float', 'composite', 'series']
books_custom_column_links = {}
cc_classes = {}
for row in cc:
if row.datatype not in cc_exceptions:
books_custom_column_links[row.id] = Table('books_custom_column_' + str(row.id) + '_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('value', Integer, ForeignKey('custom_column_' + str(row.id) + '.id'), primary_key=True)
)
cc_ids.append([row.id, row.datatype])
if row.datatype == 'bool':
ccdict = {'__tablename__': 'custom_column_' + str(row.id),
'id': Column(Integer, primary_key=True),
'book': Column(Integer, ForeignKey('books.id')),
'value': Column(Boolean)}
else:
ccdict = {'__tablename__': 'custom_column_' + str(row.id),
'id': Column(Integer, primary_key=True),
'value': Column(String)}
cc_classes[row.id] = type('Custom_Column_' + str(row.id), (Base,), ccdict)
class Identifiers(Base): class Identifiers(Base):
...@@ -243,9 +225,10 @@ class Books(Base): ...@@ -243,9 +225,10 @@ class Books(Base):
series = relationship('Series', secondary=books_series_link, backref='books') series = relationship('Series', secondary=books_series_link, backref='books')
ratings = relationship('Ratings', secondary=books_ratings_link, backref='books') ratings = relationship('Ratings', secondary=books_ratings_link, backref='books')
languages = relationship('Languages', secondary=books_languages_link, backref='books') languages = relationship('Languages', secondary=books_languages_link, backref='books')
identifiers=relationship('Identifiers', backref='books') identifiers = relationship('Identifiers', backref='books')
def __init__(self, title, sort, author_sort, timestamp, pubdate, series_index, last_modified, path, has_cover, authors, tags): def __init__(self, title, sort, author_sort, timestamp, pubdate, series_index, last_modified, path, has_cover,
authors, tags): # ToDO check Authors and tags necessary
self.title = title self.title = title
self.sort = sort self.sort = sort
self.author_sort = author_sort self.author_sort = author_sort
...@@ -260,15 +243,6 @@ class Books(Base): ...@@ -260,15 +243,6 @@ class Books(Base):
return u"<Books('{0},{1}{2}{3}{4}{5}{6}{7}{8}')>".format(self.title, self.sort, self.author_sort, return u"<Books('{0},{1}{2}{3}{4}{5}{6}{7}{8}')>".format(self.title, self.sort, self.author_sort,
self.timestamp, self.pubdate, self.series_index, self.timestamp, self.pubdate, self.series_index,
self.last_modified, self.path, self.has_cover) self.last_modified, self.path, self.has_cover)
for id in cc_ids:
if id[1] == 'bool':
setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]],
primaryjoin=(Books.id == cc_classes[id[0]].book),
backref='books'))
else:
setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]],
secondary = books_custom_column_links[id[0]],
backref='books'))
class Custom_Columns(Base): class Custom_Columns(Base):
...@@ -288,7 +262,76 @@ class Custom_Columns(Base): ...@@ -288,7 +262,76 @@ class Custom_Columns(Base):
display_dict = ast.literal_eval(self.display) display_dict = ast.literal_eval(self.display)
return display_dict return display_dict
# Base.metadata.create_all(engine)
Session = sessionmaker() def setup_db():
Session.configure(bind=engine) global session
session = Session() global cc_exceptions
global cc_classes
global cc_ids
global books_custom_column_links
global engine
if config.config_calibre_dir is None or config.config_calibre_dir == u'':
return False
dbpath = os.path.join(config.config_calibre_dir, "metadata.db")
engine = create_engine('sqlite:///{0}'.format(dbpath.encode('utf-8')), echo=False)
try:
conn = engine.connect()
except:
content = ub.session.query(ub.Settings).first()
content.config_calibre_dir = None
content.db_configured = False
ub.session.commit()
config.loadSettings()
return False
content = ub.session.query(ub.Settings).first()
content.db_configured = True
ub.session.commit()
config.loadSettings()
conn.connection.create_function('title_sort', 1, title_sort)
cc = conn.execute("SELECT id, datatype FROM custom_columns")
cc_ids = []
cc_exceptions = ['datetime', 'int', 'comments', 'float', 'composite', 'series']
books_custom_column_links = {}
cc_classes = {}
for row in cc:
if row.datatype not in cc_exceptions:
books_custom_column_links[row.id] = Table('books_custom_column_' + str(row.id) + '_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'),
primary_key=True),
Column('value', Integer,
ForeignKey('custom_column_' + str(row.id) + '.id'),
primary_key=True)
)
cc_ids.append([row.id, row.datatype])
if row.datatype == 'bool':
ccdict = {'__tablename__': 'custom_column_' + str(row.id),
'id': Column(Integer, primary_key=True),
'book': Column(Integer, ForeignKey('books.id')),
'value': Column(Boolean)}
else:
ccdict = {'__tablename__': 'custom_column_' + str(row.id),
'id': Column(Integer, primary_key=True),
'value': Column(String)}
cc_classes[row.id] = type('Custom_Column_' + str(row.id), (Base,), ccdict)
for id in cc_ids:
if id[1] == 'bool':
setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]],
primaryjoin=(
Books.id == cc_classes[id[0]].book),
backref='books'))
else:
setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]],
secondary=books_custom_column_links[id[0]],
backref='books'))
# Base.metadata.create_all(engine)
Session = sessionmaker()
Session.configure(bind=engine)
session = Session()
return True
\ No newline at end of file
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import zipfile import zipfile
from lxml import etree from lxml import etree
import os import os
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from lxml import etree from lxml import etree
import os import os
import uploader import uploader
# ToDo: Check usage of original_file_name
def get_fb2_info(tmp_file_path, original_file_name, original_file_extension): def get_fb2_info(tmp_file_path, original_file_name, original_file_extension):
ns = { ns = {
......
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<th>{{_('Passwd')}}</th> <th>{{_('Passwd')}}</th>
</tr> </tr>
{% for user in content %} {% for user in content %}
{% if not user.role_anonymous() or config.ANON_BROWSE %} {% if not user.role_anonymous() or config.config_anonbrowse %}
<tr> <tr>
<td><a href="{{url_for('edit_user', user_id=user.id)}}">{{user.nickname}}</a></td> <td><a href="{{url_for('edit_user', user_id=user.id)}}">{{user.nickname}}</a></td>
<td>{{user.email}}</td> <td>{{user.email}}</td>
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
<h2>{{_('Configuration')}}</h2> <h2>{{_('Configuration')}}</h2>
<table class="table table-striped"> <table class="table table-striped">
<tr> <tr>
<th>{{_('Log File')}}</th> <th>{{_('Calibre DB dir')}}</th>
<th>{{_('Log Level')}}</th> <th>{{_('Log Level')}}</th>
<th>{{_('Port')}}</th> <th>{{_('Port')}}</th>
<th>{{_('Books per page')}}</th> <th>{{_('Books per page')}}</th>
...@@ -65,17 +65,90 @@ ...@@ -65,17 +65,90 @@
<th>{{_('Anonymous browsing')}}</th> <th>{{_('Anonymous browsing')}}</th>
</tr> </tr>
<tr> <tr>
<td>{{config.LOG_DIR}}</td> <td>{{config.config_calibre_dir}}</td>
<td>{{config.LOG_DIR}}</td> <td>{{config.get_Log_Level()}}</td>
<td>{{config.PORT}}</td> <td>{{config.config_port}}</td>
<td>{{config.NEWEST_BOOKS}}</td> <td>{{config.config_books_per_page}}</td>
<td>{% if config.UPLOADING %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td> <td>{% if config.config_uploading %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td>
<td>{% if config.PUBLIC_REG %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td> <td>{% if config.config_public_reg %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td>
<td>{% if config.ANON_BROWSE %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td> <td>{% if config.config_anonbrowse %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td>
</table> </table>
<div class="btn btn-default"><a href="{{url_for('configuration')}}">{{_('Configuration')}}</a></div>
<h2>{{_('Administration')}}</h2> <h2>{{_('Administration')}}</h2>
{% if not config.DEVELOPMENT %} {% if not development %}
<div class="btn btn-default"><a href="{{url_for('shutdown')}}">{{_('Restart Calibre-web')}}</a></div> <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>
<a href="{{url_for('update')}}" class="btn btn-default hidden" id="perform_update">{{_('Perform Update')}}</a>
{% endif %} {% endif %}
</div> </div>
<!-- Modal -->
<div id="RestartDialog" class="modal fade" role="dialog">
<div class="modal-dialog modal-sm">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header bg-info">
</div>
<div class="modal-body text-center">
<p>{{_('Do you really want to restart Calibre-web?')}}</p>
<button type="button" class="btn btn-default" id="restart" data-dismiss="modal">{{_('Ok')}}</button>
<button type="button" class="btn btn-default" data-dismiss="modal">{{_('Back')}}</button>
</div>
</div>
</div>
</div>
<div id="ShutdownDialog" class="modal fade" role="dialog">
<div class="modal-dialog modal-sm">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header bg-info">
</div>
<div class="modal-body text-center">
<p>{{_('Do you really want to stop Calibre-web?')}}</p>
<button type="button" class="btn btn-default" id="shutdown" data-dismiss="modal">{{_('Ok')}}</button>
<button type="button" class="btn btn-default" data-dismiss="modal">{{_('Back')}}</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script type="text/javascript">
$("#restart").click(function() {
$.ajax({
dataType: 'json',
url: "{{url_for('shutdown')}}",
data: {"parameter":0},
//data: data,
success: function(data) {
return alert(data.text);}
});
});
$("#shutdown").click(function() {
$.ajax({
dataType: 'json',
url: "{{url_for('shutdown')}}",
data: {"parameter":1},
success: function(data) {
return alert(data.text);}
});
});
$("#check_for_update").click(function() {
$("#check_for_update").html('Checking...');
$.ajax({
dataType: 'json',
url: "{{url_for('get_update_status')}}",
success: function(data) {
if (data.status == true) {
$("#check_for_update").addClass('hidden');
$("#perform_update").removeClass('hidden');
}else{
$("#check_for_update").html('{{_('Check for update')}}');
};}
});
});
</script>
{% endblock %} {% endblock %}
{% extends "layout.html" %}
{% block body %}
<div class="discover">
<h1>{{title}}</h1>
<form role="form" method="POST" autocomplete="off">
<div class="form-group required">
<label for="config_calibre_dir">{{_('Location of Calibre database')}}</label>
<input type="text" class="form-control" name="config_calibre_dir" id="config_calibre_dir" value="{% if content.config_calibre_dir != None %}{{ content.config_calibre_dir }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<label for="config_port">{{_('Server Port')}}</label>
<input type="number" min="1" max="65535" class="form-control" name="config_port" id="config_port" value="{% if content.config_port != None %}{{ content.config_port }}{% endif %}" autocomplete="off" required>
</div>
<div class="form-group">
<label for="config_calibre_web_title">{{_('Title')}}</label>
<input type="text" class="form-control" name="config_calibre_web_title" id="config_calibre_web_title" value="{% if content.config_calibre_web_title != None %}{{ content.config_calibre_web_title }}{% endif %}" autocomplete="off" required>
</div>
<div class="form-group">
<label for="config_books_per_page">{{_('Books per page')}}</label>
<input type="number" min="1" max="200" class="form-control" name="config_books_per_page" id="config_books_per_page" value="{% if content.config_books_per_page != None %}{{ content.config_books_per_page }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<label for="config_random_books">{{_('No. of random books to show')}}</label>
<input type="number" min="1" max="30" class="form-control" name="config_random_books" id="config_random_books" value="{% if content.config_random_books != None %}{{ content.config_random_books }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<label for="config_title_regex">{{_('Regular expression for title sorting')}}</label>
<input type="text" class="form-control" name="config_title_regex" id="config_title_regex" value="{% if content.config_title_regex != None %}{{ content.config_title_regex }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<label for="config_log_level">{{_('Log Level')}}</label>
<select name="config_log_level" id="config_log_level" class="form-control">
<option value="10" {% if content.config_log_level == 10 %}selected{% endif %}>DEBUG</option>
<option value="20" {% if content.config_log_level == 20 or content.config_log_level == None %}selected{% endif %}>INFO</option>
<option value="30" {% if content.config_log_level == 30 %}selected{% endif %}>WARNING</option>
<option value="40" {% if content.config_log_level == 40 %}selected{% endif %}>ERROR</option>
</select>
</div>
<div class="form-group">
<input type="checkbox" id="config_uploading" name="config_uploading" {% if content.config_uploading %}checked{% endif %}>
<label for="config_uploading">{{_('Enable uploading')}}</label>
</div>
<div class="form-group">
<input type="checkbox" id="config_anonbrowse" name="config_anonbrowse" {% if content.config_anonbrowse %}checked{% endif %}>
<label for="config_anonbrowse">{{_('Enable anonymous browsing')}}</label>
</div>
<div class="form-group">
<input type="checkbox" id="config_public_reg" name="config_public_reg" {% if content.config_public_reg %}checked{% endif %}>
<label for="config_public_reg">{{_('Enable public registration')}}</label>
</div>
<button type="submit" class="btn btn-default">{{_('Submit')}}</button>
{% if not origin %}
<a href="{{ url_for('admin') }}" class="btn btn-default">{{_('Back')}}</a>
{% endif %}
{% if success %}
<a href="{{ url_for('login') }}" class="btn btn-default">{{_('Login')}}</a>
{% endif %}
</form>
</div>
{% endblock %}
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<h2>{{entry.title}}</h2> <h2>{{entry.title}}</h2>
<p class="author"> <p class="author">
{% for author in entry.authors %} {% for author in entry.authors %}
<a href="{{url_for('author', name=author.name) }}">{{author.name}}</a> <a href="{{url_for('author', id=author.id ) }}">{{author.name}}</a>
{% if not loop.last %} {% if not loop.last %}
&amp; &amp;
{% endif %} {% endif %}
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
{% endif %} {% endif %}
{% if entry.series|length > 0 %} {% if entry.series|length > 0 %}
<p>{{_('Book')}} {{entry.series_index}} {{_('of')}} <a href="{{url_for('series', name=entry.series[0].name)}}">{{entry.series[0].name}}</a></p> <p>{{_('Book')}} {{entry.series_index}} {{_('of')}} <a href="{{url_for('series', id=entry.series[0].id)}}">{{entry.series[0].name}}</a></p>
{% endif %} {% endif %}
{% if entry.languages.__len__() > 0 %} {% if entry.languages.__len__() > 0 %}
...@@ -58,20 +58,21 @@ ...@@ -58,20 +58,21 @@
</p> </p>
{% endif %} {% endif %}
{% if entry.tags|length > 0 %} {% if entry.tags|length > 0 %}
<p> <p>
<div class="tags"> <div class="tags">
<span class="glyphicon glyphicon-tags"></span> <span class="glyphicon glyphicon-tags"></span>
{% for tag in entry.tags %} {% for tag in entry.tags %}
<a href="{{ url_for('category', name=tag.name) }}" class="btn btn-xs btn-info" role="button">{{tag.name}}</a> <a href="{{ url_for('category', id=tag.id) }}" class="btn btn-xs btn-info" role="button">{{tag.name}}</a>
{%endfor%} {%endfor%}
</div> </div>
</p> </p>
{% endif %} {% endif %}
{% if entry.pubdate != '0101-01-01 00:00:00' %}
<p>{{_('Publishing date')}}: {{entry.pubdate[:10]}} </p>
{% endif %}
{% if cc|length > 0 %} {% if cc|length > 0 %}
<p> <p>
<div class="custom_columns"> <div class="custom_columns">
...@@ -101,7 +102,7 @@ ...@@ -101,7 +102,7 @@
{% endif %} {% endif %}
{% if entry.comments|length > 0 %} {% if entry.comments|length > 0 and entry.comments[0].text|length > 0%}
<h3>{{_('Description:')}}</h3> <h3>{{_('Description:')}}</h3>
{{entry.comments[0].text|safe}} {{entry.comments[0].text|safe}}
{% endif %} {% endif %}
...@@ -191,7 +192,6 @@ ...@@ -191,7 +192,6 @@
<div class="btn-toolbar" role="toolbar"> <div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group" aria-label="Edit/Delete book"> <div class="btn-group" role="group" aria-label="Edit/Delete book">
<a href="{{ url_for('edit_book', book_id=entry.id) }}" class="btn btn-sm btn-warning" role="button"><span class="glyphicon glyphicon-edit"></span> {{_('Edit metadata')}}</a> <a href="{{ url_for('edit_book', book_id=entry.id) }}" class="btn btn-sm btn-warning" role="button"><span class="glyphicon glyphicon-edit"></span> {{_('Edit metadata')}}</a>
<!-- <a href="{{ url_for('edit_book', book_id=entry.id) }}" class="btn btn-sm btn-danger" role="button"><span class="glyphicon glyphicon-trash"></span> Delete</a> -->
</div> </div>
{% endif %} {% endif %}
......
...@@ -9,13 +9,13 @@ ...@@ -9,13 +9,13 @@
<div class="cover"> <div class="cover">
{% if entry.has_cover is defined %} {% if entry.has_cover is defined %}
<a href="{{ url_for('show_book', id=entry.id) }}"> <a href="{{ url_for('show_book', id=entry.id) }}">
<img src="{{ url_for('get_cover', cover_path=entry.path) }}" /> <img src="{{ url_for('get_cover', cover_path=entry.path.replace('\\','/')) }}" />
</a> </a>
{% endif %} {% endif %}
</div> </div>
<div class="meta"> <div class="meta">
<p class="title">{{entry.title|shortentitle}}</p> <p class="title">{{entry.title|shortentitle}}</p>
<p class="author"><a href="{{url_for('author', name=entry.authors[0].name) }}">{{entry.authors[0].name}}</a></p> <p class="author"><a href="{{url_for('author', name=entry.authors[0].name | urlencode) }}">{{entry.authors[0].name}}</a></p>
{% if entry.ratings.__len__() > 0 %} {% if entry.ratings.__len__() > 0 %}
<div class="rating"> <div class="rating">
{% for number in range((entry.ratings[0].rating/2)|int(2)) %} {% for number in range((entry.ratings[0].rating/2)|int(2)) %}
......
...@@ -29,9 +29,9 @@ ...@@ -29,9 +29,9 @@
<link rel="search" <link rel="search"
href="{{url_for('feed_osd')}}" href="{{url_for('feed_osd')}}"
type="application/opensearchdescription+xml"/> type="application/opensearchdescription+xml"/>
<title>Calibre Web</title> <title>{{instance}}</title>
<author> <author>
<name>Calibre Web</name> <name>{{instance}}</name>
<uri>https://github.com/janeczku/calibre-web</uri> <uri>https://github.com/janeczku/calibre-web</uri>
</author> </author>
...@@ -60,28 +60,12 @@ ...@@ -60,28 +60,12 @@
{% endfor %} {% endfor %}
</entry> </entry>
{% endfor %} {% endfor %}
{% for author in authors %} {% for entry in listelements %}
<entry>
<title>{{author.name}}</title>
<id>{{ url_for('feed_author', id=author.id) }}</id>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_author', id=author.id)}}"/>
<link type="application/atom+xml" href="{{url_for('feed_author', id=author.id)}}" rel="subsection"/>
</entry>
{% endfor %}
{% for entry in categorys %}
<entry>
<title>{{entry.name}}</title>
<id>{{ url_for('feed_category', id=entry.id) }}</id>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_category', id=entry.id)}}"/>
<link type="application/atom+xml" href="{{url_for('feed_category', id=entry.id)}}" rel="subsection"/>
</entry>
{% endfor %}
{% for entry in series %}
<entry> <entry>
<title>{{entry.name}}</title> <title>{{entry.name}}</title>
<id>{{ url_for('feed_series', id=entry.id) }}</id> <id>{{ url_for(folder, id=entry.id) }}</id>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_series', id=entry.id)}}" /> <link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for(folder, id=entry.id)}}"/>
<link type="application/atom+xml" href="{{url_for('feed_series', id=entry.id)}}" rel="subsection"/> <link type="application/atom+xml" href="{{url_for(folder, id=entry.id)}}" rel="subsection"/>
</entry> </entry>
{% endfor %} {% endfor %}
</feed> </feed>
{% extends "layout.html" %} {% extends "layout.html" %}
{% block body %} {% block body %}
{% if g.user.show_random_books() %} {% if g.user.show_detail_random() %}
<div class="discover"> <div class="discover">
<h2>{{_('Discover (Random Books)')}}</h2> <h2>{{_('Discover (Random Books)')}}</h2>
<div class="row"> <div class="row">
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
</div> </div>
<div class="meta"> <div class="meta">
<p class="title">{{entry.title|shortentitle}}</p> <p class="title">{{entry.title|shortentitle}}</p>
<p class="author"><a href="{{url_for('author', name=entry.authors[0].name) }}">{{entry.authors[0].name}}</a></p> <p class="author"><a href="{{url_for('author', id=entry.authors[0].id) }}">{{entry.authors[0].name}}</a></p>
{% if entry.ratings.__len__() > 0 %} {% if entry.ratings.__len__() > 0 %}
<div class="rating"> <div class="rating">
{% for number in range((entry.ratings[0].rating/2)|int(2)) %} {% for number in range((entry.ratings[0].rating/2)|int(2)) %}
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
<p class="title">{{entry.title|shortentitle}}</p> <p class="title">{{entry.title|shortentitle}}</p>
<p class="author"> <p class="author">
{% for author in entry.authors %} {% for author in entry.authors %}
<a href="{{url_for('author', name=author.name) }}">{{author.name}}</a> <a href="{{url_for('author', id=author.id) }}">{{author.name}}</a>
{% if not loop.last %} {% if not loop.last %}
&amp; &amp;
{% endif %} {% endif %}
......
...@@ -6,9 +6,9 @@ ...@@ -6,9 +6,9 @@
type="application/atom+xml;profile=opds-catalog;kind=navigation"/> type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
<link rel="search" title="{{_('Search')}}" href="{{url_for('feed_osd')}}" <link rel="search" title="{{_('Search')}}" href="{{url_for('feed_osd')}}"
type="application/opensearchdescription+xml"/> type="application/opensearchdescription+xml"/>
<title>Calibre Web</title> <title>{{instance}}</title>
<author> <author>
<name>Calibre Web</name> <name>{{instance}}</name>
<uri>https://github.com/janeczku/calibre-web</uri> <uri>https://github.com/janeczku/calibre-web</uri>
</author> </author>
<entry> <entry>
......
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>calibre web | {{title}}</title> <title>{{instance}} | {{title}}</title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
{% for entry in entries %} {% for entry in entries %}
<div class="row"> <div class="row">
<div class="col-xs-1" align="left"><span class="badge">{{entry.count}}</span></div> <div class="col-xs-1" align="left"><span class="badge">{{entry.count}}</span></div>
<div class="col-xs-6"><a href="{{url_for(folder, name=entry[0].name)}}">{{entry[0].name}}</a></div> <div class="col-xs-6"><a href="{{url_for(folder, id=entry[0].id )}}">{{entry[0].name}}</a></div>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"> <OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
<LongName>Calibre Web</LongName> <LongName>{{instance}}</LongName>
<ShortName>Calibre Web</ShortName> <ShortName>{{instance}}</ShortName>
<Description>Calibre Web ebook catalog</Description> <Description>{{_('instanceCalibre Web ebook catalog')}}</Description>
<Developer>janeczku</Developer> <Developer>Janeczku</Developer>
<Contact>https://github.com/janeczku/calibre-web</Contact> <Contact>https://github.com/janeczku/calibre-web</Contact>
<Url type="text/html" <Url type="text/html"
template="{{url_for('search')}}?query={searchTerms}"/> template="{{url_for('search')}}?query={searchTerms}"/>
<Url type="application/atom+xml" <Url type="application/atom+xml"
template="{{url_for('feed_normal_search')}}?query={searchTerms}"/> template="{{url_for('feed_normal_search')}}?query={searchTerms}"/>
<SyndicationRight>open</SyndicationRight> <SyndicationRight>open</SyndicationRight>
<Language>de-DE</Language> <Language>{{lang}}</Language>
<OutputEncoding>UTF-8</OutputEncoding> <OutputEncoding>UTF-8</OutputEncoding>
<InputEncoding>UTF-8</InputEncoding> <InputEncoding>UTF-8</InputEncoding>
</OpenSearchDescription> </OpenSearchDescription>
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
<!-- Full Screen --> <!-- Full Screen -->
<!--<script src="js/libs/screenfull.min.js"></script>--> <!--<script src="js/libs/screenfull.min.js"></script>-->
<script src="{{ url_for('static', filename='js/libs/screenfull.min.js') }}"></script> <script src="{{ url_for('static', filename='js/screenfull.min.js') }}"></script>
<!-- Render --> <!-- Render -->
<!--<script src="js/epub.min.js"></script>--> <!--<script src="js/epub.min.js"></script>-->
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
<div class="cover"> <div class="cover">
{% if entry.has_cover is defined %} {% if entry.has_cover is defined %}
<a href="{{ url_for('show_book', id=entry.id) }}"> <a href="{{ url_for('show_book', id=entry.id) }}">
<img src="{{ url_for('get_cover', cover_path=entry.path) }}" /> <img src="{{ url_for('get_cover', cover_path=entry.path.replace('\\','/')) }}" />
</a> </a>
{% endif %} {% endif %}
</div> </div>
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
<p class="title">{{entry.title|shortentitle}}</p> <p class="title">{{entry.title|shortentitle}}</p>
<p class="author"> <p class="author">
{% for author in entry.authors %} {% for author in entry.authors %}
<a href="{{url_for('author', name=author.name) }}">{{author.name}}</a> <a href="{{url_for('author', name=author.name | urlencode) }}">{{author.name}}</a>
{% if not loop.last %} {% if not loop.last %}
&amp; &amp;
{% endif %} {% endif %}
...@@ -44,7 +44,6 @@ ...@@ -44,7 +44,6 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
<!-- <p><a href="{{ url_for('edit_book', book_id=entry.id) }}">{{entry.authors[0].name}}: {{entry.title}}</a></p> -->
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
......
<?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
<LongName>Calibre Web</LongName>
<ShortName>Calibre Web</ShortName>
<Description>Calibre Web ebook catalog</Description>
<Developer>janeczku</Developer>
<Contact>https://github.com/janeczku/calibre-web</Contact>
<Url type="text/html"
template="{{url_for('search')}}?query={searchTerms}"/>
<Url type="application/atom+xml"
template="{{url_for('feed_search')}}?query={searchTerms}"/>
<SyndicationRight>open</SyndicationRight>
<Language>de-DE</Language>
<OutputEncoding>UTF-8</OutputEncoding>
<InputEncoding>UTF-8</InputEncoding>
</OpenSearchDescription>
...@@ -15,13 +15,13 @@ ...@@ -15,13 +15,13 @@
<div class="cover"> <div class="cover">
{% if entry.has_cover is defined %} {% if entry.has_cover is defined %}
<a href="{{ url_for('show_book', id=entry.id) }}"> <a href="{{ url_for('show_book', id=entry.id) }}">
<img src="{{ url_for('get_cover', cover_path=entry.path) }}" /> <img src="{{ url_for('get_cover', cover_path=entry.path.replace('\\','/')) }}" />
</a> </a>
{% endif %} {% endif %}
</div> </div>
<div class="meta"> <div class="meta">
<p class="title">{{entry.title|shortentitle}}</p> <p class="title">{{entry.title|shortentitle}}</p>
<p class="author"><a href="{{url_for('author', name=entry.authors[0].name) }}">{{entry.authors[0].name}}</a></p> <p class="author"><a href="{{url_for('author', name=entry.authors[0].name | urlencode) }}">{{entry.authors[0].name}}</a></p>
{% if entry.ratings.__len__() > 0 %} {% if entry.ratings.__len__() > 0 %}
<div class="rating"> <div class="rating">
{% for number in range((entry.ratings[0].rating/2)|int(2)) %} {% for number in range((entry.ratings[0].rating/2)|int(2)) %}
...@@ -36,7 +36,6 @@ ...@@ -36,7 +36,6 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
<!-- <p><a href="{{ url_for('edit_book', book_id=entry.id) }}">{{entry.authors[0].name}}: {{entry.title}}</a></p> -->
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
......
...@@ -12,19 +12,19 @@ ...@@ -12,19 +12,19 @@
<tbody> <tbody>
<tr> <tr>
<th>Python</th> <th>Python</th>
<td>{{Versions['PythonVersion']}}</td> <td>{{versions['PythonVersion']}}</td>
</tr> </tr>
<tr> <tr>
<th>Kindlegen</th> <th>Kindlegen</th>
<td>{{Versions['KindlegenVersion']}}</td> <td>{{versions['KindlegenVersion']}}</td>
</tr> </tr>
<tr> <tr>
<th>ImageMagick</th> <th>ImageMagick</th>
<td>{{Versions['ImageVersion']}}</td> <td>{{versions['ImageVersion']}}</td>
</tr> </tr>
<tr> <tr>
<th>PyPDF2</th> <th>PyPDF2</th>
<td>{{Versions['PyPdfVersion']}}</td> <td>{{versions['PyPdfVersion']}}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
...@@ -40,6 +40,14 @@ ...@@ -40,6 +40,14 @@
<th>{{authorcounter}}</th> <th>{{authorcounter}}</th>
<td>{{_('Authors in this Library')}}</td> <td>{{_('Authors in this Library')}}</td>
</tr> </tr>
<tr>
<th>{{categorycounter}}</th>
<td>{{_('Categories in this Library')}}</td>
</tr>
<tr>
<th>{{seriecounter}}</th>
<td>{{_('Series in this Library')}}</td>
</tr>
</tbody> </tbody>
</table> </table>
{% endblock %} {% endblock %}
...@@ -27,39 +27,47 @@ ...@@ -27,39 +27,47 @@
<label for="locale">{{_('Language')}}</label> <label for="locale">{{_('Language')}}</label>
<select name="locale" id="locale" class="form-control"> <select name="locale" id="locale" class="form-control">
{% for translation in translations %} {% for translation in translations %}
<option value="{{translation}}" {% if translation|string == content.locale %}selected{% endif %}>{{ translation.display_name }}</option> <option value="{{translation.language}}" {% if translation.language == content.locale %}selected{% endif %} {% if new_user == 1 and loop.first %}selected{% endif %}>{{ translation.display_name }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="default_language">{{_('Show books with language')}}</label> <label for="default_language">{{_('Show books with language')}}</label>
<select name="default_language" id="default_language" class="form-control"> <select name="default_language" id="default_language" class="form-control">
<option value="all" >{{ _('Show all') }}</option> <option value="all" {% if new_user == 1 %}selected{% endif %}>{{ _('Show all') }}</option>
{% for language in languages %} {% for language in languages %}
<option value="{{ language.lang_code }}" {% if content.default_language == language.lang_code %}selected{% endif %}>{{ language.name }}</option> <option value="{{ language.lang_code }}" {% if content.default_language == language.lang_code %}selected{% endif %}>{{ language.name }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="checkbox" name="show_random" {% if content.random_books %}checked{% endif %}> <input type="checkbox" name="show_random" id="show_random" {% if content.show_random_books() %}checked{% endif %}>
<label for="show_random">{{_('Show random books')}}</label> <label for="show_random">{{_('Show random books')}}</label>
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="checkbox" name="show_hot" {% if content.hot_books %}checked{% endif %}> <input type="checkbox" name="show_hot" id="show_hot" {% if content.show_hot_books() %}checked{% endif %}>
<label for="show_hot">{{_('Show hot books')}}</label> <label for="show_hot">{{_('Show hot books')}}</label>
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="checkbox" name="show_language" {% if content.language_books %}checked{% endif %}> <input type="checkbox" name="show_language" id="show_language" {% if content.show_language() %}checked{% endif %}>
<label for="show_language">{{_('Show language selection')}}</label> <label for="show_language">{{_('Show language selection')}}</label>
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="checkbox" name="show_series" {% if content.series_books %}checked{% endif %}> <input type="checkbox" name="show_series" id="show_series" {% if content.show_series() %}checked{% endif %}>
<label for="show_series">{{_('Show series selection')}}</label> <label for="show_series">{{_('Show series selection')}}</label>
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="checkbox" name="show_category" {% if content.category_books %}checked{% endif %}> <input type="checkbox" name="show_category" id="show_category" {% if content.show_category() %}checked{% endif %}>
<label for="show_category">{{_('Show category selection')}}</label> <label for="show_category">{{_('Show category selection')}}</label>
</div> </div>
<div class="form-group">
<input type="checkbox" name="show_author" id="show_author" {% if content.show_author() %}checked{% endif %}>
<label for="show_author">{{_('Show author selection')}}</label>
</div>
<div class="form-group">
<input type="checkbox" name="show_detail_random" id="show_detail_random" {% if content.show_detail_random() %}checked{% endif %}>
<label for="show_detail_random">{{_('Show random books in detail view')}}</label>
</div>
{% if g.user and g.user.role_admin() and not profile %} {% if g.user and g.user.role_admin() and not profile %}
{% if not content.role_anonymous() %} {% if not content.role_anonymous() %}
...@@ -105,7 +113,7 @@ ...@@ -105,7 +113,7 @@
{% for entry in downloads %} {% for entry in downloads %}
<div class="col-sm-2"> <div class="col-sm-2">
<a class="pull-left" href="{{ url_for('show_book', id=entry.id) }}"> <a class="pull-left" href="{{ url_for('show_book', id=entry.id) }}">
<img class="media-object" width="100" src="{{ url_for('get_cover', cover_path=entry.path) }}" alt="..."> <img class="media-object" width="100" src="{{ url_for('get_cover', cover_path=entry.path.replace('\\','/')) }}" alt="...">
</a> </a>
</div> </div>
{% endfor %} {% endfor %}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os import os
from tempfile import gettempdir from tempfile import gettempdir
import hashlib import hashlib
......
This diff is collapsed.
This diff is collapsed.
...@@ -8,6 +8,7 @@ Calibre Web is a web app providing a clean interface for browsing, reading and d ...@@ -8,6 +8,7 @@ Calibre Web is a web app providing a clean interface for browsing, reading and d
##Features ##Features
- Bootstrap 3 HTML5 interface - Bootstrap 3 HTML5 interface
- full graphical setup
- User management - User management
- Admin interface - Admin interface
- User Interface in english, french, german, simplified chinese, spanish - User Interface in english, french, german, simplified chinese, spanish
...@@ -23,12 +24,14 @@ Calibre Web is a web app providing a clean interface for browsing, reading and d ...@@ -23,12 +24,14 @@ Calibre Web is a web app providing a clean interface for browsing, reading and d
- Upload new books in PDF, epub, fb2 format - Upload new books in PDF, epub, fb2 format
- Support for Calibre custom columns - Support for Calibre custom columns
- Fine grained per-user permissions - Fine grained per-user permissions
- Self update capability
## Quick start ## Quick start
1. Rename `config.ini.example` to `config.ini` and set `DB_ROOT` to the path of the folder where your Calibre library (metadata.db) lives 1. Execute the command: `python cps.py`
2. Execute the command: `python cps.py` 2. Point your browser to `http://localhost:8083` or `http://localhost:8083/opds` for the OPDS catalog
3. Point your browser to `http://localhost:8083` or `http://localhost:8083/opds` for the OPDS catalog 3. Set `Location of Calibre database` to the path of the folder where your Calibre library (metadata.db) lives, push "submit" button
4. Go to Login page
**Default admin login:** **Default admin login:**
*Username:* admin *Username:* admin
...@@ -36,12 +39,19 @@ Calibre Web is a web app providing a clean interface for browsing, reading and d ...@@ -36,12 +39,19 @@ Calibre Web is a web app providing a clean interface for browsing, reading and d
## Runtime Configuration Options ## Runtime Configuration Options
`PUBLIC_REG` The configuration can be changed as admin in the admin panel under "Configuration"
Set to 1 to enable public user registration.
`ANON_BROWSE` Server Port:
Set to 1 to allow not logged in users to browse the catalog. Changes the port calibre-web is listening, changes take effect after pressing submit button
`UPLOADING`
Set to 1 to enable PDF uploading. This requires the imagemagick library to be installed. Enable public registration:
Tick to enable public user registration.
Enable anonymous browsing:
Tick to allow not logged in users to browse the catalog, anonymous user permissions can be set as admin ("Guest" user)
Enable uploading:
Tick to enable uploading of PDF, epub, FB2. This requires the imagemagick library to be installed.
## Requirements ## Requirements
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment