Commit a75c3939 authored by Ainsley Pereira's avatar Ainsley Pereira

Merge remote-tracking branch 'upstream/master'

parents 97f573c4 b6b5313f
......@@ -27,5 +27,4 @@ tags
settings.yaml
gdrive_credentials
#kindlegen
vendor/kindlegen
vendor
# Inspired by https://github.com/ChrisTM/Flask-CacheBust
# Uses query strings so CSS font files are found without having to resort to absolute URLs
import hashlib
import os
def init_cache_busting(app):
"""
Configure `app` to so that `url_for` adds a unique query string to URLs generated
for the `'static'` endpoint.
This allows setting long cache expiration values on static resources
because whenever the resource changes, so does its URL.
"""
static_folder = os.path.join(app.static_folder, '') # path to the static file folder, with trailing slash
hash_table = {} # map of file hashes
app.logger.debug('Computing cache-busting values...')
# compute file hashes
for dirpath, dirnames, filenames in os.walk(static_folder):
for filename in filenames:
# compute version component
rooted_filename = os.path.join(dirpath, filename)
with open(rooted_filename, 'r') as f:
file_hash = hashlib.md5(f.read()).hexdigest()[:7]
# save version to tables
file_path = rooted_filename.replace(static_folder, "")
file_path = file_path.replace("\\", "/") # Convert Windows path to web path
hash_table[file_path] = file_hash
app.logger.debug('Finished computing cache-busting values')
def bust_filename(filename):
return hash_table.get(filename, "")
def unbust_filename(filename):
return filename.split("?", 1)[0]
@app.url_defaults
def reverse_to_cache_busted_url(endpoint, values):
"""
Make `url_for` produce busted filenames when using the 'static' endpoint.
"""
if endpoint == "static":
file_hash = bust_filename(values["filename"])
if file_hash:
values["q"] = file_hash
def debusting_static_view(filename):
"""
Serve a request for a static file having a busted name.
"""
return original_static_view(filename=unbust_filename(filename))
# Replace the default static file view with our debusting view.
original_static_view = app.view_functions["static"]
app.view_functions["static"] = debusting_static_view
......@@ -278,7 +278,7 @@ def get_valid_filename(value, replace_whitespace=True):
else:
value = unicode(re_slugify.sub('', value).strip())
if replace_whitespace:
#*+:\"/<>? werden durch _ ersetzt
#*+:\"/<>? are replaced by _
value = re.sub('[\*\+:\\\"/<>\?]+', u'_', value, flags=re.U)
value = value[:128]
......
......@@ -77,7 +77,8 @@ input.pill:not(:checked) + label .glyphicon {
}
.author-bio img {margin: 0 1em 1em 0;}
.author-link img {display: inline-block;max-width: 100px;}
.author-link {display: inline-block; margin-top: 10px; width: 100px;}
.author-link img {display: block; height: 100%;}
#remove-from-shelves .btn,
#shelf-action-errors {
......
<svg xmlns="http://www.w3.org/2000/svg" width="673.826" height="144" viewBox="0 0 673.826 144"><g fill="#5A481C"><path d="M66.66 86.444h-.315c-3.34 14.507-18.19 22.964-32.213 22.964C11.33 109.408 0 91.212 0 70.163c0-22.008 12.146-40.18 35.245-40.18 15.643 0 27.917 10.368 31.1 23.76h.315v-21.85h3.194v79.26C69.854 133.474 57.09 144 35.71 144c-16.576 0-30.78-7.49-31.257-25.843h3.205c.642 16.273 13.08 22.65 27.896 22.65 19.787 0 31.106-9.402 31.106-29.656V86.445zM35.245 33.176c-21.215 0-32.062 17.06-32.062 36.987 0 20.25 10.846 36.062 30.768 36.062 21.065 0 32.558-16.295 32.558-36.062.152-18.825-10.678-36.987-31.263-36.987zM115.787 29.982c23.926 0 36.825 20.58 36.825 42.897 0 22.482-12.898 42.894-36.987 42.894-23.915 0-36.853-20.41-36.853-42.895 0-22.318 12.938-42.898 37.015-42.898zm0 82.598c21.828 0 33.642-18.972 33.642-39.7 0-20.418-11.815-39.704-33.643-39.704-22.176 0-33.81 19.287-33.81 39.703 0 20.728 11.634 39.7 33.81 39.7zM194.57 29.982c23.908 0 36.824 20.58 36.824 42.897 0 22.482-12.916 42.894-36.987 42.894-23.925 0-36.84-20.41-36.84-42.895-.002-22.318 12.914-42.898 37.003-42.898zm0 82.598c21.856 0 33.643-18.972 33.643-39.7 0-20.418-11.786-39.704-33.643-39.704-22.17 0-33.822 19.287-33.822 39.703 0 20.728 11.65 39.7 33.822 39.7zM304.436 0h3.194v113.86h-3.194V90.91h-.326c-4.14 14.337-16.082 24.863-32.837 24.863-21.7 0-34.942-18.027-34.942-42.73 0-22.97 12.3-43.06 34.943-43.06 17.386 0 29.02 10.053 32.837 24.87h.326V0zm-33.163 33.176c-22.493 0-31.736 20.883-31.736 39.866 0 21.04 10.526 39.538 31.736 39.538 21.052 0 33.163-18.32 33.163-39.538 0-25.36-13.236-39.866-33.163-39.866zM323.093 31.58h9.25v19.286h.327c5.103-13.248 16.253-21.052 31.098-20.4v10.042c-18.196-.967-30.62 12.427-30.62 29.492v43.86h-10.054V31.58zM372.38 75.426c.147 14.684 7.806 32.363 27.092 32.363 14.688 0 22.65-8.604 25.832-21.03h10.064c-4.308 18.656-15.16 29.486-35.896 29.486-26.124 0-37.146-20.097-37.146-43.52 0-21.693 11.02-43.543 37.146-43.543 26.483 0 37.032 23.132 36.21 46.243h-63.3zm53.25-8.446c-.462-15.148-9.886-29.363-26.158-29.363-16.42 0-25.495 14.372-27.09 29.363h53.248zM444.297 56.775c.945-19.293 14.508-27.592 33.333-27.592 14.54 0 30.342 4.47 30.342 26.46v43.71c0 3.836 1.923 6.063 5.915 6.063 1.113 0 2.36-.326 3.183-.64v8.445c-2.238.484-3.835.642-6.557.642-10.2 0-11.82-5.735-11.82-14.36h-.28c-7.04 10.683-14.226 16.745-30.05 16.745-15.124 0-27.573-7.467-27.573-24.078 0-23.12 22.48-23.913 44.185-26.46 8.31-.978 12.933-2.09 12.933-11.172 0-13.557-9.728-16.92-21.56-16.92-12.436 0-21.67 5.76-22.03 19.16H444.3zm53.61 12.106h-.314c-1.27 2.397-5.758 3.207-8.457 3.68-17.082 3.024-38.292 2.867-38.292 18.968 0 10.054 8.93 16.262 18.342 16.262 15.317 0 28.89-9.716 28.722-25.82V68.88zM596.488 113.86h-9.232V98.24h-.326c-4.308 10.685-17.386 18.006-29.34 18.006-25.068 0-37.01-20.23-37.01-43.52 0-23.29 11.94-43.543 37.01-43.543 12.27 0 24.223 6.22 28.52 18.016h.348V0h10.03v113.86zm-38.9-6.07c21.356 0 28.868-18.017 28.868-35.063 0-17.083-7.512-35.11-28.868-35.11-19.14 0-26.956 18.027-26.956 35.11 0 17.046 7.817 35.062 26.956 35.062zM660.926 55.645c-.494-12.438-10.043-18.027-21.535-18.027-8.94 0-19.443 3.52-19.443 14.215 0 8.918 10.188 12.112 17.06 13.877l13.395 3.014c11.47 1.76 23.425 8.457 23.425 22.804 0 17.88-17.667 24.72-33.007 24.72-19.14 0-32.208-8.93-33.805-29.016h10.03c.82 13.54 10.864 20.558 24.27 20.558 9.38 0 22.47-4.14 22.47-15.62 0-9.56-8.92-12.745-18.005-14.99l-12.933-2.855c-13.068-3.51-22.976-7.984-22.976-22.008 0-16.745 16.43-23.132 30.95-23.132 16.418 0 29.52 8.625 30.14 26.46h-10.034z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 673.826 144"><g fill="#5A481C"><path d="M66.66 86.444h-.315c-3.34 14.507-18.19 22.964-32.213 22.964C11.33 109.408 0 91.212 0 70.163c0-22.008 12.146-40.18 35.245-40.18 15.643 0 27.917 10.368 31.1 23.76h.315v-21.85h3.194v79.26C69.854 133.474 57.09 144 35.71 144c-16.576 0-30.78-7.49-31.257-25.843h3.205c.642 16.273 13.08 22.65 27.896 22.65 19.787 0 31.106-9.402 31.106-29.656V86.445zM35.245 33.176c-21.215 0-32.062 17.06-32.062 36.987 0 20.25 10.846 36.062 30.768 36.062 21.065 0 32.558-16.295 32.558-36.062.152-18.825-10.678-36.987-31.263-36.987zM115.787 29.982c23.926 0 36.825 20.58 36.825 42.897 0 22.482-12.898 42.894-36.987 42.894-23.915 0-36.853-20.41-36.853-42.895 0-22.318 12.938-42.898 37.015-42.898zm0 82.598c21.828 0 33.642-18.972 33.642-39.7 0-20.418-11.815-39.704-33.643-39.704-22.176 0-33.81 19.287-33.81 39.703 0 20.728 11.634 39.7 33.81 39.7zM194.57 29.982c23.908 0 36.824 20.58 36.824 42.897 0 22.482-12.916 42.894-36.987 42.894-23.925 0-36.84-20.41-36.84-42.895-.002-22.318 12.914-42.898 37.003-42.898zm0 82.598c21.856 0 33.643-18.972 33.643-39.7 0-20.418-11.786-39.704-33.643-39.704-22.17 0-33.822 19.287-33.822 39.703 0 20.728 11.65 39.7 33.822 39.7zM304.436 0h3.194v113.86h-3.194V90.91h-.326c-4.14 14.337-16.082 24.863-32.837 24.863-21.7 0-34.942-18.027-34.942-42.73 0-22.97 12.3-43.06 34.943-43.06 17.386 0 29.02 10.053 32.837 24.87h.326V0zm-33.163 33.176c-22.493 0-31.736 20.883-31.736 39.866 0 21.04 10.526 39.538 31.736 39.538 21.052 0 33.163-18.32 33.163-39.538 0-25.36-13.236-39.866-33.163-39.866zM323.093 31.58h9.25v19.286h.327c5.103-13.248 16.253-21.052 31.098-20.4v10.042c-18.196-.967-30.62 12.427-30.62 29.492v43.86h-10.054V31.58zM372.38 75.426c.147 14.684 7.806 32.363 27.092 32.363 14.688 0 22.65-8.604 25.832-21.03h10.064c-4.308 18.656-15.16 29.486-35.896 29.486-26.124 0-37.146-20.097-37.146-43.52 0-21.693 11.02-43.543 37.146-43.543 26.483 0 37.032 23.132 36.21 46.243h-63.3zm53.25-8.446c-.462-15.148-9.886-29.363-26.158-29.363-16.42 0-25.495 14.372-27.09 29.363h53.248zM444.297 56.775c.945-19.293 14.508-27.592 33.333-27.592 14.54 0 30.342 4.47 30.342 26.46v43.71c0 3.836 1.923 6.063 5.915 6.063 1.113 0 2.36-.326 3.183-.64v8.445c-2.238.484-3.835.642-6.557.642-10.2 0-11.82-5.735-11.82-14.36h-.28c-7.04 10.683-14.226 16.745-30.05 16.745-15.124 0-27.573-7.467-27.573-24.078 0-23.12 22.48-23.913 44.185-26.46 8.31-.978 12.933-2.09 12.933-11.172 0-13.557-9.728-16.92-21.56-16.92-12.436 0-21.67 5.76-22.03 19.16H444.3zm53.61 12.106h-.314c-1.27 2.397-5.758 3.207-8.457 3.68-17.082 3.024-38.292 2.867-38.292 18.968 0 10.054 8.93 16.262 18.342 16.262 15.317 0 28.89-9.716 28.722-25.82V68.88zM596.488 113.86h-9.232V98.24h-.326c-4.308 10.685-17.386 18.006-29.34 18.006-25.068 0-37.01-20.23-37.01-43.52 0-23.29 11.94-43.543 37.01-43.543 12.27 0 24.223 6.22 28.52 18.016h.348V0h10.03v113.86zm-38.9-6.07c21.356 0 28.868-18.017 28.868-35.063 0-17.083-7.512-35.11-28.868-35.11-19.14 0-26.956 18.027-26.956 35.11 0 17.046 7.817 35.062 26.956 35.062zM660.926 55.645c-.494-12.438-10.043-18.027-21.535-18.027-8.94 0-19.443 3.52-19.443 14.215 0 8.918 10.188 12.112 17.06 13.877l13.395 3.014c11.47 1.76 23.425 8.457 23.425 22.804 0 17.88-17.667 24.72-33.007 24.72-19.14 0-32.208-8.93-33.805-29.016h10.03c.82 13.54 10.864 20.558 24.27 20.558 9.38 0 22.47-4.14 22.47-15.62 0-9.56-8.92-12.745-18.005-14.99l-12.933-2.855c-13.068-3.51-22.976-7.984-22.976-22.008 0-16.745 16.43-23.132 30.95-23.132 16.418 0 29.52 8.625 30.14 26.46h-10.034z"/></g></svg>
......@@ -4,31 +4,31 @@
/* global Bloodhound, language, Modernizr, tinymce */
if ($("#description").length) {
tinymce.init({
selector: "#description",
branding: false,
menubar: "edit view format",
language
});
tinymce.init({
selector: "#description",
branding: false,
menubar: "edit view format",
language: language
});
if (!Modernizr.inputtypes.date) {
$("#pubdate").datepicker({
format: "yyyy-mm-dd",
language
}).on("change", function () {
// Show localized date over top of the standard YYYY-MM-DD date
let pubDate;
const results = /(\d{4})[-\/\\](\d{1,2})[-\/\\](\d{1,2})/.exec(this.value); // YYYY-MM-DD
if (results) {
pubDate = new Date(results[1], parseInt(results[2], 10)-1, results[3]) || new Date(this.value);
}
$("#fake_pubdate")
.val(pubDate.toLocaleDateString(language))
.removeClass("hidden");
}).trigger("change");
}
if (!Modernizr.inputtypes.date) {
$("#pubdate").datepicker({
format: "yyyy-mm-dd",
language: language
}).on("change", function () {
// Show localized date over top of the standard YYYY-MM-DD date
var pubDate;
var results = /(\d{4})[-\/\\](\d{1,2})[-\/\\](\d{1,2})/.exec(this.value); // YYYY-MM-DD
if (results) {
pubDate = new Date(results[1], parseInt(results[2], 10) - 1, results[3]) || new Date(this.value);
}
$("#fake_pubdate")
.val(pubDate.toLocaleDateString(language))
.removeClass("hidden");
}).trigger("change");
}
}
/*
Takes a prefix, query typeahead callback, Bloodhound typeahead adapter
and returns the completions it gets from the bloodhound engine prefixed.
......@@ -43,6 +43,7 @@ function prefixedSource(prefix, query, cb, bhAdapter) {
cb(matches);
});
}
function getPath() {
var jsFileLocation = $("script[src*=edit_books]").attr("src"); // the js file path
jsFileLocation = jsFileLocation.replace("/static/js/edit_books.js", ""); // the js folder path
......@@ -56,7 +57,7 @@ var authors = new Bloodhound({
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: getPath()+"/get_authors_json?q=%QUERY"
url: getPath() + "/get_authors_json?q=%QUERY"
}
});
......@@ -69,9 +70,9 @@ var series = new Bloodhound({
return [query];
},
remote: {
url: getPath()+"/get_series_json?q=",
url: getPath() + "/get_series_json?q=",
replace: function replace(url, query) {
return url+encodeURIComponent(query);
return url + encodeURIComponent(query);
}
}
});
......@@ -84,11 +85,11 @@ var tags = new Bloodhound({
},
queryTokenizer: function queryTokenizer(query) {
var tokens = query.split(",");
tokens = [tokens[tokens.length-1].trim()];
tokens = [tokens[tokens.length - 1].trim()];
return tokens;
},
remote: {
url: getPath()+"/get_tags_json?q=%QUERY"
url: getPath() + "/get_tags_json?q=%QUERY"
}
});
......@@ -101,9 +102,9 @@ var languages = new Bloodhound({
return [query];
},
remote: {
url: getPath()+"/get_languages_json?q=",
url: getPath() + "/get_languages_json?q=",
replace: function replace(url, query) {
return url+encodeURIComponent(query);
return url + encodeURIComponent(query);
}
}
});
......@@ -112,9 +113,9 @@ function sourceSplit(query, cb, split, source) {
var bhAdapter = source.ttAdapter();
var tokens = query.split(split);
var currentSource = tokens[tokens.length-1].trim();
var currentSource = tokens[tokens.length - 1].trim();
tokens.splice(tokens.length-1, 1); // remove last element
tokens.splice(tokens.length - 1, 1); // remove last element
var prefix = "";
var newSplit;
if (split === "&") {
......@@ -192,7 +193,7 @@ promiseLanguages.done(function() {
$("#search").on("change input.typeahead:selected", function() {
var form = $("form").serialize();
$.getJSON( getPath()+"/get_matching_tags", form, function( data ) {
$.getJSON( getPath() + "/get_matching_tags", form, function( data ) {
$(".tags_click").each(function() {
if ($.inArray(parseInt($(this).children("input").first().val(), 10), data.tags) === -1 ) {
if (!($(this).hasClass("active"))) {
......
......@@ -11,16 +11,17 @@
{%if author.about is not none %}
<p>{{author.about|safe}}</p>
{% endif %}
</section>
<a href="{{author.link}}" class="author-link" target="_blank">
<img src="{{ url_for('static', filename='img/goodreads.svg') }}" alt="Goodreads">
</a>
- {{_("via")}} <a href="{{author.link}}" class="author-link" target="_blank" rel="noopener">Goodreads</a>
</section>
<div class="clearfix"></div>
{% endif %}
<div class="discover load-more">
{% if author is not none %}
<h3>{{_("In Library")}}</h3>
{% endif %}
<div class="row">
{% if entries[0] %}
{% for entry in entries %}
......@@ -62,4 +63,48 @@
{% endif %}
</div>
</div>
{% if other_books %}
<div class="discover">
<h3>{{_("More by")}} {{ author.name|safe }}</h3>
<div class="row">
{% for entry in other_books %}
<div class="col-sm-3 col-lg-2 col-xs-6 book">
<div class="cover">
<a href="https://www.goodreads.com/book/show/{{ entry.gid['#text'] }}" target="_blank" rel="noopener">
<img src="{{ entry.image_url }}" />
</a>
</div>
<div class="meta">
<p class="title">{{entry.title|shortentitle}}</p>
<p class="author">
{% for author in entry.authors %}
<a href="https://www.goodreads.com/author/show/{{ author.gid }}" target="_blank" rel="noopener">
{{author.name}}
</a>
{% if not loop.last %}
&amp;
{% endif %}
{% endfor %}
</p>
<div class="rating">
{% for number in range((entry.average_rating)|float|round|int(2)) %}
<span class="glyphicon glyphicon-star good"></span>
{% if loop.last and loop.index < 5 %}
{% for numer in range(5 - loop.index) %}
<span class="glyphicon glyphicon-star"></span>
{% endfor %}
{% endif %}
{% endfor %}
</div>
</div>
</div>
{% endfor %}
</div>
<a href="{{author.link}}" class="author-link" target="_blank" rel="noopener">
<img src="{{ url_for('static', filename='img/goodreads.svg') }}" alt="Goodreads">
</a>
</div>
{% endif %}
{% endblock %}
......@@ -26,9 +26,7 @@
href="{{request.script_root + request.path}}?offset={{ pagination.previous_offset }}"
type="application/atom+xml;profile=opds-catalog;type=feed;kind=navigation"/>
{% endif %}
<link rel="search"
href="{{url_for('feed_osd')}}"
type="application/opensearchdescription+xml"/>
<link title="{{_('Search')}}" type="application/atom+xml" href="{{url_for('feed_normal_search')}}?query={searchTerms}" rel="search"/>
<title>{{instance}}</title>
<author>
<name>{{instance}}</name>
......
......@@ -4,8 +4,7 @@
<link rel="self" href="{{url_for('feed_index')}}" type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
<link rel="start" title="{{_('Start')}}" href="{{url_for('feed_index')}}"
type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
<link rel="search" title="{{_('Search')}}" href="{{url_for('feed_osd')}}"
type="application/opensearchdescription+xml"/>
<link title="{{_('Search')}}" type="application/atom+xml" href="{{url_for('feed_normal_search')}}?query={searchTerms}" rel="search"/>
<title>{{instance}}</title>
<author>
<name>{{instance}}</name>
......
......@@ -4,7 +4,7 @@
{% if entries|length < 1 %}
<h2>{{_('No Results for:')}} {{searchterm}}</h2>
<p>{{_('Please try a diffrent Search')}}</p>
<p>{{_('Please try a different search')}}</p>
{% else %}
<h2>{{entries|length}} {{_('Results for:')}} {{searchterm}}</h2>
{%endif%}
......
......@@ -41,10 +41,6 @@
</select>
</div>
<div class="col-sm-6">
<div class="form-group">
<input type="checkbox" name="show_mature_content" id="show_mature_content" {% if content.mature_content %}checked{% endif %}>
<label for="show_mature_content">{{_('Show mature content')}}</label>
</div>
<div class="form-group">
<input type="checkbox" name="show_random" id="show_random" {% if content.show_random_books() %}checked{% endif %}>
<label for="show_random">{{_('Show random books')}}</label>
......@@ -88,6 +84,10 @@
<div class="form-group">
<input type="checkbox" name="admin_role" id="admin_role" {% if content.role_admin() %}checked{% endif %}>
<label for="admin_role">{{_('Admin user')}}</label>
</div>
<div class="form-group">
<input type="checkbox" name="show_mature_content" id="show_mature_content" {% if content.mature_content %}checked{% endif %}>
<label for="show_mature_content">{{_('Show mature content')}}</label>
</div>
{% endif %}
<div class="form-group">
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -11,4 +11,5 @@ PyYAML==3.12
rsa==3.4.2
six==1.10.0
uritemplate==3.0.0
goodreads==0.3.2
\ No newline at end of file
goodreads>=0.3.2
python-Levenshtein>=0.12.0
......@@ -30,7 +30,7 @@ Calibre Web is a web app providing a clean interface for browsing, reading and d
## Quick start
1. Install required dependencies by executing `pip install -r requirements.txt`
1. Install dependencies by running `pip install --target vendor -r requirements.txt`.
2. Execute the command: `python cps.py` (or `nohup python cps.py` - recommended if you want to exit the terminal window)
3. Point your browser to `http://localhost:8083` or `http://localhost:8083/opds` for the OPDS catalog
4. Set `Location of Calibre database` to the path of the folder where your Calibre library (metadata.db) lives, push "submit" button
......@@ -70,7 +70,7 @@ Optionally, to enable on-the-fly conversion from EPUB to MOBI when using the sen
## Using Google Drive integration
Additional optional dependencys are necessary to get this work. Please install all optional requirements by executing `pip install -r optional-requirements.txt`
Additional optional dependencys are necessary to get this work. Please install all optional requirements by executing `pip install --target vendor -r optional-requirements.txt`
To use google drive integration, you have to use the google developer console to create a new app. https://console.developers.google.com
......
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