Merge branch 'master' into develop
# Conflicts: # cps/db.py # cps/ub.py # cps/web.py # readme.md # requirements.txt
This commit is contained in:
+5
-5
@@ -14,28 +14,28 @@ try:
|
||||
from wand.image import Image
|
||||
from wand import version as ImageVersion
|
||||
use_generic_pdf_cover = False
|
||||
except ImportError, e:
|
||||
except ImportError as e:
|
||||
logger.warning('cannot import Image, generating pdf covers for pdf uploads will not work: %s', e)
|
||||
use_generic_pdf_cover = True
|
||||
try:
|
||||
from PyPDF2 import PdfFileReader
|
||||
from PyPDF2 import __version__ as PyPdfVersion
|
||||
use_pdf_meta = True
|
||||
except ImportError, e:
|
||||
except ImportError as e:
|
||||
logger.warning('cannot import PyPDF2, extracting pdf metadata will not work: %s', e)
|
||||
use_pdf_meta = False
|
||||
|
||||
try:
|
||||
import epub
|
||||
use_epub_meta = True
|
||||
except ImportError, e:
|
||||
except ImportError as e:
|
||||
logger.warning('cannot import epub, extracting epub metadata will not work: %s', e)
|
||||
use_epub_meta = False
|
||||
|
||||
try:
|
||||
import fb2
|
||||
use_fb2_meta = True
|
||||
except ImportError, e:
|
||||
except ImportError as e:
|
||||
logger.warning('cannot import fb2, extracting fb2 metadata will not work: %s', e)
|
||||
use_fb2_meta = False
|
||||
|
||||
@@ -48,7 +48,7 @@ def process(tmp_file_path, original_file_name, original_file_extension):
|
||||
return epub.get_epub_info(tmp_file_path, original_file_name, original_file_extension)
|
||||
if ".FB2" == original_file_extension.upper() and use_fb2_meta is True:
|
||||
return fb2.get_fb2_info(tmp_file_path, original_file_extension)
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
logger.warning('cannot parse metadata, using default: %s', e)
|
||||
return default_meta(tmp_file_path, original_file_name, original_file_extension)
|
||||
|
||||
|
||||
@@ -11,10 +11,8 @@ from ub import config
|
||||
import ub
|
||||
|
||||
session = None
|
||||
cc_exceptions = None
|
||||
cc_classes = {}
|
||||
cc_ids = []
|
||||
books_custom_column_links = {}
|
||||
cc_exceptions = ['datetime', 'int', 'comments', 'float', 'composite', 'series']
|
||||
cc_classes = None
|
||||
engine = None
|
||||
|
||||
|
||||
@@ -283,24 +281,19 @@ class Custom_Columns(Base):
|
||||
|
||||
|
||||
def setup_db():
|
||||
global session
|
||||
global cc_exceptions
|
||||
global cc_classes
|
||||
global cc_ids
|
||||
global books_custom_column_links
|
||||
global engine
|
||||
global session
|
||||
global cc_classes
|
||||
|
||||
if config.config_calibre_dir is None or config.config_calibre_dir == u'':
|
||||
return False
|
||||
|
||||
dbpath = os.path.join(config.config_calibre_dir, "metadata.db")
|
||||
if not os.path.exists(dbpath):
|
||||
return False
|
||||
engine = create_engine('sqlite:///{0}'.format(dbpath.encode('utf-8')), echo=False)
|
||||
#engine = create_engine('sqlite:///{0}'.format(dbpath.encode('utf-8')), echo=False, isolation_level="SERIALIZABLE")
|
||||
engine = create_engine('sqlite:///'+ dbpath, echo=False, isolation_level="SERIALIZABLE")
|
||||
try:
|
||||
conn = engine.connect()
|
||||
|
||||
except:
|
||||
except Exception as e:
|
||||
content = ub.session.query(ub.Settings).first()
|
||||
content.config_calibre_dir = None
|
||||
content.db_configured = False
|
||||
@@ -313,19 +306,21 @@ def setup_db():
|
||||
config.loadSettings()
|
||||
conn.connection.create_function('title_sort', 1, title_sort)
|
||||
|
||||
cc = conn.execute("SELECT id, datatype FROM custom_columns")
|
||||
if not cc_classes:
|
||||
cc = conn.execute("SELECT id, datatype FROM custom_columns")
|
||||
|
||||
cc_exceptions = ['datetime', 'int', 'comments', 'float', 'composite', 'series']
|
||||
for row in cc:
|
||||
if row.datatype not in cc_exceptions:
|
||||
if row.id not in books_custom_column_links:
|
||||
cc_ids = []
|
||||
books_custom_column_links = {}
|
||||
cc_classes = {}
|
||||
for row in cc:
|
||||
if row.datatype not in cc_exceptions:
|
||||
books_custom_column_links[row.id] = Table('books_custom_column_' + str(row.id) + '_link', Base.metadata,
|
||||
Column('book', Integer, ForeignKey('books.id'),
|
||||
primary_key=True),
|
||||
Column('value', Integer,
|
||||
ForeignKey('custom_column_' + str(row.id) + '.id'),
|
||||
primary_key=True)
|
||||
)
|
||||
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),
|
||||
@@ -338,8 +333,7 @@ def setup_db():
|
||||
'value': Column(String)}
|
||||
cc_classes[row.id] = type('Custom_Column_' + str(row.id), (Base,), ccdict)
|
||||
|
||||
for id in cc_ids:
|
||||
if not hasattr(Books, 'custom_column_' + str(id[0])):
|
||||
for id in cc_ids:
|
||||
if id[1] == 'bool':
|
||||
setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]],
|
||||
primaryjoin=(
|
||||
|
||||
+7
-5
@@ -4,8 +4,10 @@
|
||||
from lxml import etree
|
||||
import os
|
||||
import uploader
|
||||
import StringIO
|
||||
|
||||
try:
|
||||
from io import StringIO
|
||||
except ImportError as e:
|
||||
import StringIO
|
||||
|
||||
def get_fb2_info(tmp_file_path, original_file_extension):
|
||||
|
||||
@@ -37,16 +39,16 @@ def get_fb2_info(tmp_file_path, original_file_extension):
|
||||
first_name = u''
|
||||
return first_name + ' ' + middle_name + ' ' + last_name
|
||||
|
||||
author = unicode(", ".join(map(get_author, authors)))
|
||||
author = str(", ".join(map(get_author, authors)))
|
||||
|
||||
title = tree.xpath('/fb:FictionBook/fb:description/fb:title-info/fb:book-title/text()', namespaces=ns)
|
||||
if len(title):
|
||||
title = unicode(title[0])
|
||||
title = str(title[0])
|
||||
else:
|
||||
title = u''
|
||||
description = tree.xpath('/fb:FictionBook/fb:description/fb:publish-info/fb:book-name/text()', namespaces=ns)
|
||||
if len(description):
|
||||
description = unicode(description[0])
|
||||
description = str(description[0])
|
||||
else:
|
||||
description = u''
|
||||
|
||||
|
||||
+20
-10
@@ -13,11 +13,18 @@ import os
|
||||
import traceback
|
||||
import re
|
||||
import unicodedata
|
||||
from StringIO import StringIO
|
||||
try:
|
||||
from StringIO import StringIO
|
||||
from email.MIMEBase import MIMEBase
|
||||
from email.MIMEMultipart import MIMEMultipart
|
||||
from email.MIMEText import MIMEText
|
||||
except ImportError as e:
|
||||
from io import StringIO
|
||||
from email.mime.base import MIMEBase
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
|
||||
from email import encoders
|
||||
from email.MIMEBase import MIMEBase
|
||||
from email.MIMEMultipart import MIMEMultipart
|
||||
from email.MIMEText import MIMEText
|
||||
from email.generator import Generator
|
||||
from email.utils import formatdate
|
||||
from email.utils import make_msgid
|
||||
@@ -34,7 +41,7 @@ import web
|
||||
try:
|
||||
import unidecode
|
||||
use_unidecode=True
|
||||
except:
|
||||
except Exception as e:
|
||||
use_unidecode=False
|
||||
|
||||
# Global variables
|
||||
@@ -149,7 +156,7 @@ def send_raw_email(kindle_mail, msg):
|
||||
|
||||
smtplib.stderr = org_stderr
|
||||
|
||||
except (socket.error, smtplib.SMTPRecipientsRefused, smtplib.SMTPException), e:
|
||||
except (socket.error, smtplib.SMTPRecipientsRefused, smtplib.SMTPException) as e:
|
||||
app.logger.error(traceback.print_exc())
|
||||
return _("Failed to send mail: %s" % str(e))
|
||||
|
||||
@@ -240,8 +247,11 @@ def get_valid_filename(value, replace_whitespace=True):
|
||||
value=value.replace(u'§',u'SS')
|
||||
value=value.replace(u'ß',u'ss')
|
||||
value = unicodedata.normalize('NFKD', value)
|
||||
re_slugify = re.compile('[^\w\s-]', re.UNICODE)
|
||||
value = unicode(re_slugify.sub('', value).strip())
|
||||
re_slugify = re.compile('[\W\s-]', re.UNICODE)
|
||||
if type(value) is str: #Python3 str, Python2 unicode
|
||||
value = re_slugify.sub('', value).strip()
|
||||
else:
|
||||
value = unicode(re_slugify.sub('', value).strip())
|
||||
if replace_whitespace:
|
||||
#*+:\"/<>? werden durch _ ersetzt
|
||||
value = re.sub('[\*\+:\\\"/<>\?]+', u'_', value, flags=re.U)
|
||||
@@ -405,7 +415,7 @@ class Updater(threading.Thread):
|
||||
try:
|
||||
os.chown(dst_file, permission.st_uid, permission.st_uid)
|
||||
# print('Permissions: User '+str(new_permissions.st_uid)+' Group '+str(new_permissions.st_uid))
|
||||
except:
|
||||
except Exception as e:
|
||||
e = sys.exc_info()
|
||||
logging.getLogger('cps.web').debug('Fail '+str(dst_file)+' error: '+str(e))
|
||||
return
|
||||
@@ -447,7 +457,7 @@ class Updater(threading.Thread):
|
||||
logging.getLogger('cps.web').debug("Delete file " + item_path)
|
||||
log_from_thread("Delete file " + item_path)
|
||||
os.remove(item_path)
|
||||
except:
|
||||
except Exception as e:
|
||||
logging.getLogger('cps.web').debug("Could not remove:" + item_path)
|
||||
shutil.rmtree(source, ignore_errors=True)
|
||||
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Get Metadata from Douban Books api and Google Books api
|
||||
* Created by idalin<dalin.lin@gmail.com>
|
||||
* Google Books api document: https://developers.google.com/books/docs/v1/using
|
||||
* Douban Books api document: https://developers.douban.com/wiki/?title=book_v2 (Chinese Only)
|
||||
*/
|
||||
|
||||
$(document).ready(function () {
|
||||
var msg = i18n_msg;
|
||||
var douban = 'https://api.douban.com';
|
||||
var db_search = '/v2/book/search';
|
||||
var db_get_info = '/v2/book/';
|
||||
var db_get_info_by_isbn = '/v2/book/isbn/ ';
|
||||
var db_done = false;
|
||||
|
||||
var google = 'https://www.googleapis.com/';
|
||||
var gg_search = '/books/v1/volumes';
|
||||
var gg_get_info = '/books/v1/volumes/';
|
||||
var gg_done = false;
|
||||
|
||||
var db_results = [];
|
||||
var gg_results = [];
|
||||
var show_flag = 0;
|
||||
String.prototype.replaceAll = function (s1, s2) {
|
||||
return this.replace(new RegExp(s1, "gm"), s2);
|
||||
}
|
||||
|
||||
gg_search_book = function (title) {
|
||||
title = title.replaceAll(/\s+/, '+');
|
||||
var url = google + gg_search + '?q=' + title;
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: "GET",
|
||||
dataType: "jsonp",
|
||||
jsonp: 'callback',
|
||||
success: function (data) {
|
||||
gg_results = data.items;
|
||||
},
|
||||
complete: function () {
|
||||
gg_done = true;
|
||||
show_result();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get_meta = function (source, id) {
|
||||
var meta;
|
||||
if (source == 'google') {;
|
||||
meta = gg_results[id];
|
||||
$('#description').val(meta.volumeInfo.description);
|
||||
$('#bookAuthor').val(meta.volumeInfo.authors.join(' & '));
|
||||
$('#book_title').val(meta.volumeInfo.title);
|
||||
if (meta.volumeInfo.categories) {
|
||||
var tags = meta.volumeInfo.categories.join(',');
|
||||
$('#tags').val(tags);
|
||||
}
|
||||
if (meta.volumeInfo.averageRating) {
|
||||
$('#rating').val(Math.round(meta.volumeInfo.averageRating));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (source == 'douban') {
|
||||
meta = db_results[id];
|
||||
$('#description').val(meta.summary);
|
||||
$('#bookAuthor').val(meta.author.join(' & '));
|
||||
$('#book_title').val(meta.title);
|
||||
var tags = '';
|
||||
for (var i = 0; i < meta.tags.length; i++) {
|
||||
tags = tags + meta.tags[i].title + ',';
|
||||
}
|
||||
$('#tags').val(tags);
|
||||
$('#rating').val(Math.round(meta.rating.average / 2));
|
||||
return;
|
||||
}
|
||||
}
|
||||
do_search = function (keyword) {
|
||||
show_flag = 0;
|
||||
$('#meta-info').text(msg.loading);
|
||||
var keyword = $('#keyword').val();
|
||||
if (keyword) {
|
||||
db_search_book(keyword);
|
||||
gg_search_book(keyword);
|
||||
}
|
||||
}
|
||||
|
||||
db_search_book = function (title) {
|
||||
var url = douban + db_search + '?q=' + title + '&fields=all&count=10';
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: "GET",
|
||||
dataType: "jsonp",
|
||||
jsonp: 'callback',
|
||||
success: function (data) {
|
||||
db_results = data.books;
|
||||
},
|
||||
error: function () {
|
||||
$('#meta-info').html('<p class="text-danger">'+ msg.search_error+'!</p>');
|
||||
},
|
||||
complete: function () {
|
||||
db_done = true;
|
||||
show_result();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
show_result = function () {
|
||||
show_flag++;
|
||||
if (show_flag == 1) {
|
||||
$('#meta-info').html('<ul id="book-list" class="media-list"></ul>');
|
||||
}
|
||||
if (gg_done && db_done) {
|
||||
if (!gg_results && !db_results) {
|
||||
$('#meta-info').html('<p class="text-danger">'+ msg.no_result +'</p>');
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (gg_done && gg_results.length > 0) {
|
||||
for (var i = 0; i < gg_results.length; i++) {
|
||||
var book = gg_results[i];
|
||||
var book_cover;
|
||||
if (book.volumeInfo.imageLinks) {
|
||||
book_cover = book.volumeInfo.imageLinks.thumbnail;
|
||||
} else {
|
||||
book_cover = '/static/generic_cover.jpg';
|
||||
}
|
||||
var book_html = '<li class="media">' +
|
||||
'<img class="pull-left img-responsive" data-toggle="modal" data-target="#metaModal" src="' +
|
||||
book_cover + '" alt="Cover" style="width:100px;height:150px" onclick=\'javascript:get_meta("google",' +
|
||||
i + ')\'>' +
|
||||
'<div class="media-body">' +
|
||||
'<h4 class="media-heading"><a href="https://books.google.com/books?id=' +
|
||||
book.id + '" target="_blank">' + book.volumeInfo.title + '</a></h4>' +
|
||||
'<p>'+ msg.author +':' + book.volumeInfo.authors + '</p>' +
|
||||
'<p>'+ msg.publisher + ':' + book.volumeInfo.publisher + '</p>' +
|
||||
'<p>'+ msg.description + ':' + book.volumeInfo.description + '</p>' +
|
||||
'<p>'+ msg.source + ':<a href="https://books.google.com" target="_blank">Google Books</a></p>' +
|
||||
'</div>' +
|
||||
'</li>';
|
||||
$("#book-list").append(book_html);
|
||||
}
|
||||
gg_done = false;
|
||||
}
|
||||
if (db_done && db_results.length > 0) {
|
||||
for (var i = 0; i < db_results.length; i++) {
|
||||
var book = db_results[i];
|
||||
var book_html = '<li class="media">' +
|
||||
'<img class="pull-left img-responsive" data-toggle="modal" data-target="#metaModal" src="' +
|
||||
book.image + '" alt="Cover" style="width:100px;height: 150px" onclick=\'javascript:get_meta("douban",' +
|
||||
i + ')\'>' +
|
||||
'<div class="media-body">' +
|
||||
'<h4 class="media-heading"><a href="https://book.douban.com/subject/' +
|
||||
book.id + '" target="_blank">' + book.title + '</a></h4>' +
|
||||
'<p>' + msg.author + ':' + book.author + '</p>' +
|
||||
'<p>' + msg.publisher + ':' + book.publisher + '</p>' +
|
||||
'<p>' + msg.description + ':' + book.summary + '</p>' +
|
||||
'<p>' + msg.source + ':<a href="https://book.douban.com" target="_blank">Douban Books</a></p>' +
|
||||
'</div>' +
|
||||
'</li>';
|
||||
$("#book-list").append(book_html);
|
||||
}
|
||||
db_done = false;
|
||||
}
|
||||
}
|
||||
|
||||
$('#do-search').click(function () {
|
||||
var keyword = $('#keyword').val();
|
||||
if (keyword) {
|
||||
do_search(keyword);
|
||||
}
|
||||
});
|
||||
|
||||
$('#get_meta').click(function () {
|
||||
var book_title = $('#book_title').val();
|
||||
if (book_title) {
|
||||
$('#keyword').val(book_title);
|
||||
do_search(book_title);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
!function(a){"use strict";function b(a){return"[data-value"+(a?"="+a:"")+"]"}function c(a,b,c){var d=c.activeIcon,e=c.inactiveIcon;a.removeClass(b?e:d).addClass(b?d:e)}function d(b,c){var d=a.extend({},i,b.data(),c);return d.inline=""===d.inline||d.inline,d.readonly=""===d.readonly||d.readonly,d.clearable===!1?d.clearableLabel="":d.clearableLabel=d.clearable,d.clearable=""===d.clearable||d.clearable,d}function e(b,c){if(c.inline)var d=a('<span class="rating-input"></span>');else var d=a('<div class="rating-input"></div>');d.addClass(b.attr("class")),d.removeClass("rating");for(var e=c.min;e<=c.max;e++)d.append('<i class="'+c.iconLib+'" data-value="'+e+'"></i>');return c.clearable&&!c.readonly&&d.append(" ").append('<a class="'+f+'"><i class="'+c.iconLib+" "+c.clearableIcon+'"/>'+c.clearableLabel+"</a>"),d}var f="rating-clear",g="."+f,h="hidden",i={min:1,max:5,"empty-value":0,iconLib:"glyphicon",activeIcon:"glyphicon-star",inactiveIcon:"glyphicon-star-empty",clearable:!1,clearableIcon:"glyphicon-remove",clearableRemain:!1,inline:!1,readonly:!1},j=function(a,b){var c=this.$input=a;this.options=d(c,b);var f=this.$el=e(c,this.options);c.addClass(h).before(f),c.attr("type","hidden"),this.highlight(c.val())};j.VERSION="0.4.0",j.DEFAULTS=i,j.prototype={clear:function(){this.setValue(this.options["empty-value"])},setValue:function(a){this.highlight(a),this.updateInput(a)},highlight:function(a,d){var e=this.options,f=this.$el;if(a>=this.options.min&&a<=this.options.max){var i=f.find(b(a));c(i.prevAll("i").andSelf(),!0,e),c(i.nextAll("i"),!1,e)}else c(f.find(b()),!1,e);d||(this.options.clearableRemain?f.find(g).removeClass(h):a&&a!=this.options["empty-value"]?f.find(g).removeClass(h):f.find(g).addClass(h))},updateInput:function(a){var b=this.$input;b.val()!=a&&b.val(a).change()}};var k=a.fn.rating=function(c){return this.filter("input[type=number]").each(function(){var d=a(this),e="object"==typeof c&&c||{},f=new j(d,e);f.options.readonly||f.$el.on("mouseenter",b(),function(){f.highlight(a(this).data("value"),!0)}).on("mouseleave",b(),function(){f.highlight(d.val(),!0)}).on("click",b(),function(){f.setValue(a(this).data("value"))}).on("click",g,function(){f.clear()})})};k.Constructor=j,a(function(){a("input.rating[type=number]").each(function(){a(this).rating()})})}(jQuery);
|
||||
@@ -65,6 +65,13 @@ $(function() {
|
||||
}
|
||||
});
|
||||
});
|
||||
$("#restart_database").click(function() {
|
||||
$.ajax({
|
||||
dataType: 'json',
|
||||
url: window.location.pathname+"/../../shutdown",
|
||||
data: {"parameter":2}
|
||||
});
|
||||
});
|
||||
$("#perform_update").click(function() {
|
||||
$('#spinner2').show();
|
||||
$.ajax({
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
<div>{{_('Current commit timestamp')}}: <span>{{commit}} </span></div>
|
||||
<div class="hidden" id="update_info">{{_('Newest commit timestamp')}}: <span></span></div>
|
||||
<p></p>
|
||||
<div class="btn btn-default" id="restart_database">{{_('Reconnect to Calibre DB')}}</div>
|
||||
<div class="btn btn-default" data-toggle="modal" data-target="#RestartDialog">{{_('Restart Calibre-web')}}</div>
|
||||
<div class="btn btn-default" data-toggle="modal" data-target="#ShutdownDialog">{{_('Stop Calibre-web')}}</div>
|
||||
<div class="btn btn-default" id="check_for_update">{{_('Check for update')}}</div>
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="rating">{{_('Rating')}}</label>
|
||||
<input type="number" min="0" max="5" step="1" class="form-control" name="rating" id="rating" value="{% if book.ratings %}{{book.ratings[0].rating / 2}}{% endif %}">
|
||||
<input type="number" name="rating" id="rating" class="rating input-lg" data-clearable="" value="{% if book.ratings %}{{(book.ratings[0].rating / 2)|int}}{% endif %}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="cover_url">{{_('Cover URL (jpg)')}}</label>
|
||||
@@ -104,16 +104,56 @@
|
||||
<input name="detail_view" type="checkbox" checked> {{_('view book after edit')}}
|
||||
</label>
|
||||
</div>
|
||||
<a href="#" id="get_meta" class="btn btn-default" data-toggle="modal" data-target="#metaModal">{{_('Get Metadata')}}</a>
|
||||
<button type="submit" class="btn btn-default">{{_('Submit')}}</button>
|
||||
<a href="{{ url_for('show_book',id=book.id) }}" class="btn btn-default">{{_('Back')}}</a>
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="modal fade" id="metaModal" tabindex="-1" role="dialog" aria-labelledby="metaModalLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="metaModalLabel">{{_('Get metadata')}}</h4>
|
||||
<form class="form-inline">
|
||||
<div class="form-group">
|
||||
<label class="sr-only" for="keyword">{{_('Keyword')}}</label>
|
||||
<input type="text" class="form-control" id="keyword" placeholder="{{_(" Search keyword ")}}">
|
||||
</div>
|
||||
<button type="button" class="btn btn-default" id="do-search">{{_("Go!")}}</button>
|
||||
<span>{{_('Click the cover to load metadata to the form')}}</span>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-body" id="meta-info">
|
||||
{{_("Loading...")}}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{_('Close')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script>
|
||||
var i18n_msg = {
|
||||
'loading': {{_('Loading...')|safe|tojson}},
|
||||
'search_error': {{_('Search error!')|safe|tojson}},
|
||||
'no_result': {{_('No Result! Please try anonther keyword.')|safe|tojson}},
|
||||
'author': {{_('Author')|safe|tojson}},
|
||||
'publisher': {{_('Publisher')|safe|tojson}},
|
||||
'description': {{_('Description')|safe|tojson}},
|
||||
'source': {{_('Source')|safe|tojson}},
|
||||
};
|
||||
</script>
|
||||
<script src="{{ url_for('static', filename='js/libs/typeahead.bundle.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/edit_books.js') }}"></script>
|
||||
<<<<<<< HEAD
|
||||
<script src="{{ url_for('static', filename='js/libs/bootstrap-rating-input.min.js') }}"></script>
|
||||
=======
|
||||
<script src="{{ url_for('static', filename='js/get_meta.js') }}"></script>
|
||||
{% endblock %}
|
||||
{% block header %}
|
||||
<link href="{{ url_for('static', filename='css/libs/typeahead.css') }}" rel="stylesheet" media="screen">
|
||||
|
||||
@@ -62,7 +62,10 @@
|
||||
<label for="config_random_books">{{_('No. of random books to show')}}</label>
|
||||
<input type="number" min="1" max="30" class="form-control" name="config_random_books" id="config_random_books" value="{% if content.config_random_books != None %}{{ content.config_random_books }}{% endif %}" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="config_columns_to_ignore">{{_('Regular expression for ignoring columns')}}</label>
|
||||
<input type="text" class="form-control" name="config_columns_to_ignore" id="config_columns_to_ignore" value="{% if content.config_columns_to_ignore != None %}{{ content.config_columns_to_ignore }}{% endif %}" autocomplete="off">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="config_title_regex">{{_('Regular expression for title sorting')}}</label>
|
||||
<input type="text" class="form-control" name="config_title_regex" id="config_title_regex" value="{% if content.config_title_regex != None %}{{ content.config_title_regex }}{% endif %}" autocomplete="off">
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
<uri>https://github.com/janeczku/calibre-web</uri>
|
||||
</author>
|
||||
|
||||
{% if entries[0] %}
|
||||
{% for entry in entries %}
|
||||
<entry>
|
||||
<title>{{entry.title}}</title>
|
||||
@@ -60,6 +61,7 @@
|
||||
{% endfor %}
|
||||
</entry>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% for entry in listelements %}
|
||||
<entry>
|
||||
<title>{{entry.name}}</title>
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
<div class="discover load-more">
|
||||
<h2>{{title}}</h2>
|
||||
<div class="row">
|
||||
{% if entries[0] %}
|
||||
{% for entry in entries %}
|
||||
<div id="books" class="col-sm-3 col-lg-2 col-xs-6 book">
|
||||
<div class="cover">
|
||||
@@ -76,6 +77,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
Binary file not shown.
@@ -325,7 +325,7 @@ msgstr "发送测试邮件时发生错误: %(res)s"
|
||||
|
||||
#: cps/web.py:1816
|
||||
msgid "E-Mail settings updated"
|
||||
msgstr ""
|
||||
msgstr "E-Mail 设置已更新"
|
||||
|
||||
#: cps/web.py:1817
|
||||
msgid "Edit mail settings"
|
||||
@@ -357,11 +357,11 @@ msgstr "编辑元数据"
|
||||
#: cps/web.py:2162
|
||||
#, python-format
|
||||
msgid "File extension \"%s\" is not allowed to be uploaded to this server"
|
||||
msgstr ""
|
||||
msgstr "不能上传后缀为 \"%s\" 的文件到此服务器"
|
||||
|
||||
#: cps/web.py:2168
|
||||
msgid "File to be uploaded must have an extension"
|
||||
msgstr ""
|
||||
msgstr "要上传的文件必须有一个后缀"
|
||||
|
||||
#: cps/web.py:2185
|
||||
#, python-format
|
||||
|
||||
@@ -11,6 +11,7 @@ import logging
|
||||
from werkzeug.security import generate_password_hash
|
||||
from flask_babel import gettext as _
|
||||
import json
|
||||
#from builtins import str
|
||||
|
||||
dbpath = os.path.join(os.path.normpath(os.path.dirname(os.path.realpath(__file__)) + os.sep + ".." + os.sep), "app.db")
|
||||
engine = create_engine('sqlite:///{0}'.format(dbpath), echo=False)
|
||||
@@ -92,7 +93,7 @@ class UserBase:
|
||||
return False
|
||||
|
||||
def get_id(self):
|
||||
return unicode(self.id)
|
||||
return str(self.id)
|
||||
|
||||
def filter_language(self):
|
||||
return self.default_language
|
||||
@@ -269,6 +270,7 @@ class Settings(Base):
|
||||
config_anonbrowse = Column(SmallInteger, default=0)
|
||||
config_public_reg = Column(SmallInteger, default=0)
|
||||
config_default_role = Column(SmallInteger, default=0)
|
||||
config_columns_to_ignore = Column(String)
|
||||
config_use_google_drive = Column(Boolean)
|
||||
config_google_drive_client_id = Column(String)
|
||||
config_google_drive_client_secret = Column(String)
|
||||
@@ -301,6 +303,7 @@ class Config:
|
||||
self.config_anonbrowse = data.config_anonbrowse
|
||||
self.config_public_reg = data.config_public_reg
|
||||
self.config_default_role = data.config_default_role
|
||||
self.config_columns_to_ignore = data.config_columns_to_ignore
|
||||
self.config_use_google_drive = data.config_use_google_drive
|
||||
self.config_google_drive_client_id = data.config_google_drive_client_id
|
||||
self.config_google_drive_client_secret = data.config_google_drive_client_secret
|
||||
@@ -406,6 +409,12 @@ def migrate_Database():
|
||||
conn.execute("ALTER TABLE Settings ADD column `config_google_drive_calibre_url_base` INTEGER DEFAULT 0")
|
||||
conn.execute("ALTER TABLE Settings ADD column `config_google_drive_folder` String DEFAULT ''")
|
||||
conn.execute("ALTER TABLE Settings ADD column `config_google_drive_watch_changes_response` String DEFAULT ''")
|
||||
try:
|
||||
session.query(exists().where(Settings.config_columns_to_ignore)).scalar()
|
||||
except exc.OperationalError:
|
||||
conn = engine.connect()
|
||||
conn.execute("ALTER TABLE Settings ADD column `config_columns_to_ignore` String DEFAULT ''")
|
||||
session.commit()
|
||||
try:
|
||||
session.query(exists().where(Settings.config_default_role)).scalar()
|
||||
session.commit()
|
||||
@@ -484,7 +493,7 @@ def create_anonymous_user():
|
||||
session.add(user)
|
||||
try:
|
||||
session.commit()
|
||||
except:
|
||||
except Exception as e:
|
||||
session.rollback()
|
||||
pass
|
||||
|
||||
@@ -503,7 +512,7 @@ def create_admin_user():
|
||||
session.add(user)
|
||||
try:
|
||||
session.commit()
|
||||
except:
|
||||
except Exception as e:
|
||||
session.rollback()
|
||||
pass
|
||||
|
||||
|
||||
+82
-34
@@ -21,9 +21,8 @@ from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy import __version__ as sqlalchemyVersion
|
||||
from math import ceil
|
||||
from flask_login import LoginManager, login_user, logout_user, login_required, current_user
|
||||
from flask_login import __version__ as flask_loginVersion
|
||||
from flask_principal import Principal, Identity, AnonymousIdentity, identity_changed
|
||||
from flask_login import __version__ as flask_principalVersion
|
||||
from flask_principal import __version__ as flask_principalVersion
|
||||
from flask_babel import Babel
|
||||
from flask_babel import gettext as _
|
||||
import requests
|
||||
@@ -59,6 +58,18 @@ import threading
|
||||
|
||||
from tornado import version as tornadoVersion
|
||||
|
||||
try:
|
||||
from urllib.parse import quote
|
||||
from imp import reload
|
||||
from past.builtins import xrange
|
||||
except ImportError as e:
|
||||
from urllib import quote
|
||||
|
||||
try:
|
||||
from flask_login import __version__ as flask_loginVersion
|
||||
except ImportError, e:
|
||||
from flask_login.__about__ import __version__ as flask_loginVersion
|
||||
|
||||
import time
|
||||
|
||||
current_milli_time = lambda: int(round(time.time() * 1000))
|
||||
@@ -67,7 +78,7 @@ try:
|
||||
from wand.image import Image
|
||||
|
||||
use_generic_pdf_cover = False
|
||||
except ImportError, e:
|
||||
except ImportError as e:
|
||||
use_generic_pdf_cover = True
|
||||
from cgi import escape
|
||||
|
||||
@@ -209,6 +220,15 @@ lm.anonymous_user = ub.Anonymous
|
||||
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
|
||||
db.setup_db()
|
||||
|
||||
if config.config_log_level == logging.DEBUG :
|
||||
logging.getLogger("sqlalchemy.engine").addHandler(file_handler)
|
||||
logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO)
|
||||
logging.getLogger("sqlalchemy.pool").addHandler(file_handler)
|
||||
logging.getLogger("sqlalchemy.pool").setLevel(config.config_log_level)
|
||||
logging.getLogger("sqlalchemy.orm").addHandler(file_handler)
|
||||
logging.getLogger("sqlalchemy.orm").setLevel(config.config_log_level)
|
||||
|
||||
|
||||
def is_gdrive_ready():
|
||||
return os.path.exists('settings.yaml') and os.path.exists('gdrive_credentials')
|
||||
|
||||
@@ -361,7 +381,7 @@ def shortentitle_filter(s):
|
||||
def mimetype_filter(val):
|
||||
try:
|
||||
s = mimetypes.types_map['.' + val]
|
||||
except:
|
||||
except Exception as e:
|
||||
s = 'application/octet-stream'
|
||||
return s
|
||||
|
||||
@@ -643,7 +663,13 @@ def feed_hot():
|
||||
hot_books = all_books.offset(off).limit(config.config_books_per_page)
|
||||
entries = list()
|
||||
for book in hot_books:
|
||||
entries.append(db.session.query(db.Books).filter(filter).filter(db.Books.id == book.Downloads.book_id).first())
|
||||
downloadBook = db.session.query(db.Books).filter(db.Books.id == book.Downloads.book_id).first()
|
||||
if downloadBook:
|
||||
entries.append(
|
||||
db.session.query(db.Books).filter(filter).filter(db.Books.id == book.Downloads.book_id).first())
|
||||
else:
|
||||
ub.session.query(ub.Downloads).filter(book.Downloads.book_id == ub.Downloads.book_id).delete()
|
||||
ub.session.commit()
|
||||
numBooks = entries.__len__()
|
||||
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, numBooks)
|
||||
xml = render_title_template('feed.xml', entries=entries, pagination=pagination)
|
||||
@@ -881,7 +907,7 @@ def get_updater_status():
|
||||
elif request.method == "GET":
|
||||
try:
|
||||
status['status']=helper.updater_thread.get_update_status()
|
||||
except:
|
||||
except Exception as e:
|
||||
status['status'] = 7
|
||||
return json.dumps(status)
|
||||
|
||||
@@ -896,7 +922,7 @@ def get_languages_json():
|
||||
try:
|
||||
cur_l = LC.parse(lang.lang_code)
|
||||
lang.name = cur_l.get_language_name(get_locale())
|
||||
except:
|
||||
except Exception as e:
|
||||
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
||||
entries = [s for s in languages if query in s.name.lower()]
|
||||
json_dumps = json.dumps([dict(name=r.name) for r in entries])
|
||||
@@ -966,9 +992,13 @@ def hot_books(page):
|
||||
hot_books = all_books.offset(off).limit(config.config_books_per_page)
|
||||
entries = list()
|
||||
for book in hot_books:
|
||||
entry=db.session.query(db.Books).filter(filter).filter(db.Books.id == book.Downloads.book_id).first()
|
||||
if entry:
|
||||
entries.append(entry)
|
||||
downloadBook = db.session.query(db.Books).filter(db.Books.id == book.Downloads.book_id).first()
|
||||
if downloadBook:
|
||||
entries.append(
|
||||
db.session.query(db.Books).filter(filter).filter(db.Books.id == book.Downloads.book_id).first())
|
||||
else:
|
||||
ub.session.query(ub.Downloads).filter(book.Downloads.book_id == ub.Downloads.book_id).delete()
|
||||
ub.session.commit()
|
||||
numBooks = entries.__len__()
|
||||
pagination = Pagination(page, config.config_books_per_page, numBooks)
|
||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
||||
@@ -1058,13 +1088,13 @@ def language_overview():
|
||||
try:
|
||||
cur_l = LC.parse(lang.lang_code)
|
||||
lang.name = cur_l.get_language_name(get_locale())
|
||||
except:
|
||||
except Exception as e:
|
||||
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
||||
else:
|
||||
try:
|
||||
langfound = 1
|
||||
cur_l = LC.parse(current_user.filter_language())
|
||||
except:
|
||||
except Exception as e:
|
||||
langfound = 0
|
||||
languages = db.session.query(db.Languages).filter(
|
||||
db.Languages.lang_code == current_user.filter_language()).all()
|
||||
@@ -1088,7 +1118,7 @@ def language(name, page):
|
||||
try:
|
||||
cur_l = LC.parse(name)
|
||||
name = cur_l.get_language_name(get_locale())
|
||||
except:
|
||||
except Exception as e:
|
||||
name = _(isoLanguages.get(part3=name).name)
|
||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
||||
title=_(u"Language: %(name)s", name=name))
|
||||
@@ -1149,10 +1179,19 @@ def show_book(id):
|
||||
try:
|
||||
entries.languages[index].language_name = LC.parse(entries.languages[index].lang_code).get_language_name(
|
||||
get_locale())
|
||||
except:
|
||||
except Exception as e:
|
||||
entries.languages[index].language_name = _(
|
||||
isoLanguages.get(part3=entries.languages[index].lang_code).name)
|
||||
cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
|
||||
tmpcc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
|
||||
|
||||
if config.config_columns_to_ignore:
|
||||
cc=[]
|
||||
for col in tmpcc:
|
||||
r= re.compile(config.config_columns_to_ignore)
|
||||
if r.match(col.label):
|
||||
cc.append(col)
|
||||
else:
|
||||
cc=tmpcc
|
||||
book_in_shelfs = []
|
||||
shelfs = ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == id).all()
|
||||
for entry in shelfs:
|
||||
@@ -1199,6 +1238,8 @@ def stats():
|
||||
stdin=subprocess.PIPE)
|
||||
p.wait()
|
||||
for lines in p.stdout.readlines():
|
||||
if type(lines) is bytes:
|
||||
lines = lines.decode('utf-8')
|
||||
if re.search('Amazon kindlegen\(', lines):
|
||||
versions['KindlegenVersion'] = lines
|
||||
versions['PythonVersion'] = sys.version
|
||||
@@ -1334,6 +1375,11 @@ def shutdown():
|
||||
showtext['text'] = _(u'Performing shutdown of server, please close window')
|
||||
return json.dumps(showtext)
|
||||
else:
|
||||
if task == 2:
|
||||
db.session.close()
|
||||
db.engine.dispose()
|
||||
db.setup_db()
|
||||
return json.dumps({})
|
||||
abort(404)
|
||||
|
||||
@app.route("/update")
|
||||
@@ -1396,7 +1442,7 @@ def advanced_search():
|
||||
try:
|
||||
cur_l = LC.parse(lang.lang_code)
|
||||
lang.name = cur_l.get_language_name(get_locale())
|
||||
except:
|
||||
except Exception as e:
|
||||
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
||||
searchterm.extend(language.name for language in language_names)
|
||||
searchterm = " + ".join(filter(None, searchterm))
|
||||
@@ -1428,7 +1474,7 @@ def advanced_search():
|
||||
try:
|
||||
cur_l = LC.parse(lang.lang_code)
|
||||
lang.name = cur_l.get_language_name(get_locale())
|
||||
except:
|
||||
except Exception as e:
|
||||
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
||||
else:
|
||||
languages = None
|
||||
@@ -1553,22 +1599,22 @@ def read_book(book_id, format):
|
||||
zfile.close()
|
||||
return render_title_template('read.html', bookid=book_id, title=_(u"Read a Book"))
|
||||
elif format.lower() == "pdf":
|
||||
all_name = str(book_id) + "/" + urllib.quote(book.data[0].name) + ".pdf"
|
||||
tmp_file = os.path.join(book_dir, urllib.quote(book.data[0].name)) + ".pdf"
|
||||
all_name = str(book_id) + "/" + book.data[0].name + ".pdf"
|
||||
tmp_file = os.path.join(book_dir, book.data[0].name) + ".pdf"
|
||||
if not os.path.exists(tmp_file):
|
||||
pdf_file = os.path.join(config.config_calibre_dir, book.path, book.data[0].name) + ".pdf"
|
||||
copyfile(pdf_file, tmp_file)
|
||||
return render_title_template('readpdf.html', pdffile=all_name, title=_(u"Read a Book"))
|
||||
elif format.lower() == "txt":
|
||||
all_name = str(book_id) + "/" + urllib.quote(book.data[0].name) + ".txt"
|
||||
tmp_file = os.path.join(book_dir, urllib.quote(book.data[0].name)) + ".txt"
|
||||
all_name = str(book_id) + "/" + book.data[0].name + ".txt"
|
||||
tmp_file = os.path.join(book_dir, book.data[0].name) + ".txt"
|
||||
if not os.path.exists(all_name):
|
||||
txt_file = os.path.join(config.config_calibre_dir, book.path, book.data[0].name) + ".txt"
|
||||
copyfile(txt_file, tmp_file)
|
||||
return render_title_template('readtxt.html', txtfile=all_name, title=_(u"Read a Book"))
|
||||
elif format.lower() == "cbr":
|
||||
all_name = str(book_id) + "/" + urllib.quote(book.data[0].name) + ".cbr"
|
||||
tmp_file = os.path.join(book_dir, urllib.quote(book.data[0].name)) + ".cbr"
|
||||
all_name = str(book_id) + "/" + book.data[0].name + ".cbr"
|
||||
tmp_file = os.path.join(book_dir, book.data[0].name) + ".cbr"
|
||||
if not os.path.exists(all_name):
|
||||
cbr_file = os.path.join(config.config_calibre_dir, book.path, book.data[0].name) + ".cbr"
|
||||
copyfile(cbr_file, tmp_file)
|
||||
@@ -1635,7 +1681,7 @@ def register():
|
||||
try:
|
||||
ub.session.add(content)
|
||||
ub.session.commit()
|
||||
except:
|
||||
except Exception as e:
|
||||
ub.session.rollback()
|
||||
flash(_(u"An unknown error occured. Please try again later."), category="error")
|
||||
return render_title_template('register.html', title=_(u"register"))
|
||||
@@ -1760,7 +1806,7 @@ def create_shelf():
|
||||
ub.session.add(shelf)
|
||||
ub.session.commit()
|
||||
flash(_(u"Shelf %(title)s created", title=to_save["title"]), category="success")
|
||||
except:
|
||||
except Exception as e:
|
||||
flash(_(u"There was an error"), category="error")
|
||||
return render_title_template('shelf_edit.html', shelf=shelf, title=_(u"create a shelf"))
|
||||
else:
|
||||
@@ -1788,7 +1834,7 @@ def edit_shelf(shelf_id):
|
||||
try:
|
||||
ub.session.commit()
|
||||
flash(_(u"Shelf %(title)s changed", title=to_save["title"]), category="success")
|
||||
except:
|
||||
except Exception as e:
|
||||
flash(_(u"There was an error"), category="error")
|
||||
return render_title_template('shelf_edit.html', shelf=shelf, title=_(u"Edit a shelf"))
|
||||
else:
|
||||
@@ -1876,7 +1922,7 @@ def profile():
|
||||
try:
|
||||
cur_l = LC.parse(lang.lang_code)
|
||||
lang.name = cur_l.get_language_name(get_locale())
|
||||
except:
|
||||
except Exception as e:
|
||||
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
||||
translations = babel.list_translations() + [LC('en')]
|
||||
for book in content.downloads:
|
||||
@@ -2007,6 +2053,8 @@ def configuration_helper(origin):
|
||||
reboot_required = True
|
||||
if "config_calibre_web_title" in to_save:
|
||||
content.config_calibre_web_title = to_save["config_calibre_web_title"]
|
||||
if "config_columns_to_ignore" in to_save:
|
||||
content.config_columns_to_ignore = to_save["config_columns_to_ignore"]
|
||||
if "config_title_regex" in to_save:
|
||||
if content.config_title_regex != to_save["config_title_regex"]:
|
||||
content.config_title_regex = to_save["config_title_regex"]
|
||||
@@ -2086,7 +2134,7 @@ def new_user():
|
||||
try:
|
||||
cur_l = LC.parse(lang.lang_code)
|
||||
lang.name = cur_l.get_language_name(get_locale())
|
||||
except:
|
||||
except Exception as e:
|
||||
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
||||
translations = [LC('en')] + babel.list_translations()
|
||||
if request.method == "POST":
|
||||
@@ -2186,7 +2234,7 @@ def edit_user(user_id):
|
||||
try:
|
||||
cur_l = LC.parse(lang.lang_code)
|
||||
lang.name = cur_l.get_language_name(get_locale())
|
||||
except:
|
||||
except Exception as e:
|
||||
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
||||
translations = babel.list_translations() + [LC('en')]
|
||||
for book in content.downloads:
|
||||
@@ -2313,7 +2361,7 @@ def edit_book(book_id):
|
||||
try:
|
||||
book.languages[index].language_name = LC.parse(book.languages[index].lang_code).get_language_name(
|
||||
get_locale())
|
||||
except:
|
||||
except Exception as e:
|
||||
book.languages[index].language_name = _(isoLanguages.get(part3=book.languages[index].lang_code).name)
|
||||
for author in book.authors:
|
||||
author_names.append(author.name)
|
||||
@@ -2363,7 +2411,7 @@ def edit_book(book_id):
|
||||
for lang in languages:
|
||||
try:
|
||||
lang.name = LC.parse(lang.lang_code).get_language_name(get_locale()).lower()
|
||||
except:
|
||||
except Exception as e:
|
||||
lang.name = _(isoLanguages.get(part3=lang.lang_code).name).lower()
|
||||
for inp_lang in input_languages:
|
||||
if inp_lang == lang.name:
|
||||
@@ -2554,12 +2602,12 @@ def upload():
|
||||
return redirect(url_for('index'))
|
||||
try:
|
||||
copyfile(meta.file_path, saved_filename)
|
||||
except OSError, e:
|
||||
except OSError as e:
|
||||
flash(_(u"Failed to store file %s (Permission denied)." % saved_filename), category="error")
|
||||
return redirect(url_for('index'))
|
||||
try:
|
||||
os.unlink(meta.file_path)
|
||||
except OSError, e:
|
||||
except OSError as e:
|
||||
flash(_(u"Failed to delete file %s (Permission denied)." % meta.file_path), category="warning")
|
||||
|
||||
file_size = os.path.getsize(saved_filename)
|
||||
@@ -2591,7 +2639,7 @@ def upload():
|
||||
db.session.add(db_language)
|
||||
# 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,
|
||||
db_book = db.Books(title, "", db_author.sort, datetime.datetime.now(), datetime.datetime(101, 1, 1), 1,
|
||||
datetime.datetime.now(), path, has_cover, db_author, [], db_language)
|
||||
db_book.authors.append(db_author)
|
||||
if db_language is not None:
|
||||
|
||||
Reference in New Issue
Block a user