Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
D
douban-api-proxy
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
captainwong
douban-api-proxy
Commits
9c1b3f13
Commit
9c1b3f13
authored
Mar 16, 2019
by
Ozzieisaacs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improved sorting for rated,random, hot books, read/unread book
parent
a66873a9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
445 additions
and
426 deletions
+445
-426
admin.py
cps/admin.py
+3
-2
editbooks.py
cps/editbooks.py
+2
-1
helper.py
cps/helper.py
+112
-0
opds.py
cps/opds.py
+2
-2
discover.html
cps/templates/discover.html
+0
-1
index.html
cps/templates/index.html
+7
-7
layout.html
cps/templates/layout.html
+1
-13
ub.py
cps/ub.py
+6
-6
web.py
cps/web.py
+312
-394
No files found.
cps/admin.py
View file @
9c1b3f13
...
@@ -25,8 +25,8 @@ import os
...
@@ -25,8 +25,8 @@ import os
from
flask
import
Blueprint
,
flash
,
redirect
,
url_for
from
flask
import
Blueprint
,
flash
,
redirect
,
url_for
from
flask
import
abort
,
request
,
make_response
from
flask
import
abort
,
request
,
make_response
from
flask_login
import
login_required
,
current_user
,
logout_user
from
flask_login
import
login_required
,
current_user
,
logout_user
from
web
import
admin_required
,
render_title_template
,
before_request
,
speaking_language
,
unconfigured
,
\
from
web
import
admin_required
,
render_title_template
,
before_request
,
unconfigured
,
\
login_required_if_no_ano
,
check_valid_domain
login_required_if_no_ano
from
cps
import
db
,
ub
,
Server
,
get_locale
,
config
,
app
,
updater_thread
,
babel
from
cps
import
db
,
ub
,
Server
,
get_locale
,
config
,
app
,
updater_thread
,
babel
import
json
import
json
from
datetime
import
datetime
,
timedelta
from
datetime
import
datetime
,
timedelta
...
@@ -37,6 +37,7 @@ from babel import Locale as LC
...
@@ -37,6 +37,7 @@ from babel import Locale as LC
from
sqlalchemy.exc
import
IntegrityError
from
sqlalchemy.exc
import
IntegrityError
from
gdriveutils
import
is_gdrive_ready
,
gdrive_support
,
downloadFile
,
deleteDatabaseOnChange
,
listRootFolders
from
gdriveutils
import
is_gdrive_ready
,
gdrive_support
,
downloadFile
,
deleteDatabaseOnChange
,
listRootFolders
import
helper
import
helper
from
helper
import
speaking_language
,
check_valid_domain
from
werkzeug.security
import
generate_password_hash
from
werkzeug.security
import
generate_password_hash
try
:
try
:
from
imp
import
reload
from
imp
import
reload
...
...
cps/editbooks.py
View file @
9c1b3f13
...
@@ -31,8 +31,9 @@ import json
...
@@ -31,8 +31,9 @@ import json
from
flask_babel
import
gettext
as
_
from
flask_babel
import
gettext
as
_
from
uuid
import
uuid4
from
uuid
import
uuid4
import
helper
import
helper
from
helper
import
order_authors
,
common_filters
from
flask_login
import
current_user
from
flask_login
import
current_user
from
web
import
login_required_if_no_ano
,
common_filters
,
order_authors
,
render_title_template
,
edit_required
,
\
from
web
import
login_required_if_no_ano
,
render_title_template
,
edit_required
,
\
upload_required
,
login_required
,
EXTENSIONS_UPLOAD
upload_required
,
login_required
,
EXTENSIONS_UPLOAD
import
gdriveutils
import
gdriveutils
from
shutil
import
move
,
copyfile
from
shutil
import
move
,
copyfile
...
...
cps/helper.py
View file @
9c1b3f13
...
@@ -32,9 +32,15 @@ from flask import send_from_directory, make_response, redirect, abort
...
@@ -32,9 +32,15 @@ from flask import send_from_directory, make_response, redirect, abort
from
flask_babel
import
gettext
as
_
from
flask_babel
import
gettext
as
_
from
flask_login
import
current_user
from
flask_login
import
current_user
from
babel.dates
import
format_datetime
from
babel.dates
import
format_datetime
from
babel.core
import
UnknownLocaleError
from
datetime
import
datetime
from
datetime
import
datetime
from
babel
import
Locale
as
LC
import
shutil
import
shutil
import
requests
import
requests
from
sqlalchemy.sql.expression
import
true
,
and_
,
false
,
text
,
func
from
iso639
import
languages
as
isoLanguages
from
pagination
import
Pagination
try
:
try
:
import
gdriveutils
as
gd
import
gdriveutils
as
gd
except
ImportError
:
except
ImportError
:
...
@@ -558,3 +564,109 @@ def render_task_status(tasklist):
...
@@ -558,3 +564,109 @@ def render_task_status(tasklist):
renderedtasklist
.
append
(
task
)
renderedtasklist
.
append
(
task
)
return
renderedtasklist
return
renderedtasklist
# Language and content filters for displaying in the UI
def
common_filters
():
if
current_user
.
filter_language
()
!=
"all"
:
lang_filter
=
db
.
Books
.
languages
.
any
(
db
.
Languages
.
lang_code
==
current_user
.
filter_language
())
else
:
lang_filter
=
true
()
content_rating_filter
=
false
()
if
current_user
.
mature_content
else
\
db
.
Books
.
tags
.
any
(
db
.
Tags
.
name
.
in_
(
config
.
mature_content_tags
()))
return
and_
(
lang_filter
,
~
content_rating_filter
)
# Creates for all stored languages a translated speaking name in the array for the UI
def
speaking_language
(
languages
=
None
):
if
not
languages
:
languages
=
db
.
session
.
query
(
db
.
Languages
)
.
all
()
for
lang
in
languages
:
try
:
cur_l
=
LC
.
parse
(
lang
.
lang_code
)
lang
.
name
=
cur_l
.
get_language_name
(
get_locale
())
except
UnknownLocaleError
:
lang
.
name
=
_
(
isoLanguages
.
get
(
part3
=
lang
.
lang_code
)
.
name
)
return
languages
# checks if domain is in database (including wildcards)
# example SELECT * FROM @TABLE WHERE 'abcdefg' LIKE Name;
# from https://code.luasoftware.com/tutorials/flask/execute-raw-sql-in-flask-sqlalchemy/
def
check_valid_domain
(
domain_text
):
domain_text
=
domain_text
.
split
(
'@'
,
1
)[
-
1
]
.
lower
()
sql
=
"SELECT * FROM registration WHERE :domain LIKE domain;"
result
=
ub
.
session
.
query
(
ub
.
Registration
)
.
from_statement
(
text
(
sql
))
.
params
(
domain
=
domain_text
)
.
all
()
return
len
(
result
)
# Orders all Authors in the list according to authors sort
def
order_authors
(
entry
):
sort_authors
=
entry
.
author_sort
.
split
(
'&'
)
authors_ordered
=
list
()
error
=
False
for
auth
in
sort_authors
:
# ToDo: How to handle not found authorname
result
=
db
.
session
.
query
(
db
.
Authors
)
.
filter
(
db
.
Authors
.
sort
==
auth
.
lstrip
()
.
strip
())
.
first
()
if
not
result
:
error
=
True
break
authors_ordered
.
append
(
result
)
if
not
error
:
entry
.
authors
=
authors_ordered
return
entry
# Fill indexpage with all requested data from database
def
fill_indexpage
(
page
,
database
,
db_filter
,
order
,
*
join
):
if
current_user
.
show_detail_random
():
randm
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
common_filters
())
\
.
order_by
(
func
.
random
())
.
limit
(
config
.
config_random_books
)
else
:
randm
=
false
()
off
=
int
(
int
(
config
.
config_books_per_page
)
*
(
page
-
1
))
pagination
=
Pagination
(
page
,
config
.
config_books_per_page
,
len
(
db
.
session
.
query
(
database
)
.
filter
(
db_filter
)
.
filter
(
common_filters
())
.
all
()))
entries
=
db
.
session
.
query
(
database
)
.
join
(
*
join
,
isouter
=
True
)
.
filter
(
db_filter
)
.
filter
(
common_filters
())
.
\
order_by
(
*
order
)
.
offset
(
off
)
.
limit
(
config
.
config_books_per_page
)
.
all
()
for
book
in
entries
:
book
=
order_authors
(
book
)
return
entries
,
randm
,
pagination
# read search results from calibre-database and return it (function is used for feed and simple search
def
get_search_results
(
term
):
q
=
list
()
authorterms
=
re
.
split
(
"[, ]+"
,
term
)
for
authorterm
in
authorterms
:
q
.
append
(
db
.
Books
.
authors
.
any
(
db
.
Authors
.
name
.
ilike
(
"
%
"
+
authorterm
+
"
%
"
)))
db
.
session
.
connection
()
.
connection
.
connection
.
create_function
(
"lower"
,
1
,
db
.
lcase
)
db
.
Books
.
authors
.
any
(
db
.
Authors
.
name
.
ilike
(
"
%
"
+
term
+
"
%
"
))
return
db
.
session
.
query
(
db
.
Books
)
.
filter
(
common_filters
())
.
filter
(
db
.
or_
(
db
.
Books
.
tags
.
any
(
db
.
Tags
.
name
.
ilike
(
"
%
"
+
term
+
"
%
"
)),
db
.
Books
.
series
.
any
(
db
.
Series
.
name
.
ilike
(
"
%
"
+
term
+
"
%
"
)),
db
.
Books
.
authors
.
any
(
and_
(
*
q
)),
db
.
Books
.
publishers
.
any
(
db
.
Publishers
.
name
.
ilike
(
"
%
"
+
term
+
"
%
"
)),
db
.
Books
.
title
.
ilike
(
"
%
"
+
term
+
"
%
"
)))
.
all
()
def
get_unique_other_books
(
library_books
,
author_books
):
# Get all identifiers (ISBN, Goodreads, etc) and filter author's books by that list so we show fewer duplicates
# Note: Not all images will be shown, even though they're available on Goodreads.com.
# See https://www.goodreads.com/topic/show/18213769-goodreads-book-images
identifiers
=
reduce
(
lambda
acc
,
book
:
acc
+
map
(
lambda
identifier
:
identifier
.
val
,
book
.
identifiers
),
library_books
,
[])
other_books
=
filter
(
lambda
book
:
book
.
isbn
not
in
identifiers
and
book
.
gid
[
"#text"
]
not
in
identifiers
,
author_books
)
# Fuzzy match book titles
if
feature_support
[
'levenshtein'
]:
library_titles
=
reduce
(
lambda
acc
,
book
:
acc
+
[
book
.
title
],
library_books
,
[])
other_books
=
filter
(
lambda
author_book
:
not
filter
(
lambda
library_book
:
# Remove items in parentheses before comparing
Levenshtein
.
ratio
(
re
.
sub
(
r"\(.*\)"
,
""
,
author_book
.
title
),
library_book
)
>
0.7
,
library_titles
),
other_books
)
return
other_books
cps/opds.py
View file @
9c1b3f13
...
@@ -30,12 +30,12 @@ import datetime
...
@@ -30,12 +30,12 @@ import datetime
import
ub
import
ub
from
flask_login
import
current_user
from
flask_login
import
current_user
from
functools
import
wraps
from
functools
import
wraps
from
web
import
login_required_if_no_ano
,
fill_indexpage
,
common_filters
,
get_search_results
,
render_read_books
from
web
import
login_required_if_no_ano
,
common_filters
,
get_search_results
,
render_read_books
,
download_required
from
sqlalchemy.sql.expression
import
func
,
text
from
sqlalchemy.sql.expression
import
func
,
text
import
helper
import
helper
from
werkzeug.security
import
check_password_hash
from
werkzeug.security
import
check_password_hash
from
werkzeug.datastructures
import
Headers
from
werkzeug.datastructures
import
Headers
from
web
import
download_required
from
helper
import
fill_indexpage
import
sys
import
sys
try
:
try
:
...
...
cps/templates/discover.html
View file @
9c1b3f13
...
@@ -3,7 +3,6 @@
...
@@ -3,7 +3,6 @@
<div
class=
"discover load-more"
>
<div
class=
"discover load-more"
>
<h2>
{{title}}
</h2>
<h2>
{{title}}
</h2>
<div
class=
"row"
>
<div
class=
"row"
>
{% for entry in entries %}
{% for entry in entries %}
<div
class=
"col-sm-3 col-lg-2 col-xs-6 book"
>
<div
class=
"col-sm-3 col-lg-2 col-xs-6 book"
>
<div
class=
"cover"
>
<div
class=
"cover"
>
...
...
cps/templates/index.html
View file @
9c1b3f13
...
@@ -58,14 +58,14 @@ web. {% for entry in random %}
...
@@ -58,14 +58,14 @@ web. {% for entry in random %}
<div
class=
"discover load-more"
>
<div
class=
"discover load-more"
>
<h2
class=
"{{title}}"
>
{{_(title)}}
</h2>
<h2
class=
"{{title}}"
>
{{_(title)}}
</h2>
<div
class=
"filterheader hidden-xs hidden-sm"
>
<div
class=
"filterheader hidden-xs hidden-sm"
>
<a
id=
"new"
class=
"btn btn-primary"
href=
"{{url_for('web.
newest_books
')}}"
><span
class=
"glyphicon glyphicon-sort-by-order"
></span></a>
<a
id=
"new"
class=
"btn btn-primary"
href=
"{{url_for('web.
books_list', data=page, sort='new
')}}"
><span
class=
"glyphicon glyphicon-sort-by-order"
></span></a>
<a
id=
"old"
class=
"btn btn-primary"
href=
"{{url_for('web.
oldest_books
')}}"
><span
class=
"glyphicon glyphicon-sort-by-order-alt"
></span></a>
<a
id=
"old"
class=
"btn btn-primary"
href=
"{{url_for('web.
books_list', data=page, sort='old
')}}"
><span
class=
"glyphicon glyphicon-sort-by-order-alt"
></span></a>
<a
id=
"asc"
class=
"btn btn-primary"
href=
"{{url_for('web.
titles_ascending
')}}"
><span
class=
"glyphicon glyphicon-font"
></span><span
class=
"glyphicon glyphicon-sort-by-alphabet"
></span></a>
<a
id=
"asc"
class=
"btn btn-primary"
href=
"{{url_for('web.
books_list', data=page, sort='abc
')}}"
><span
class=
"glyphicon glyphicon-font"
></span><span
class=
"glyphicon glyphicon-sort-by-alphabet"
></span></a>
<a
id=
"desc"
class=
"btn btn-primary"
href=
"{{url_for('web.
titles_descending
')}}"
><span
class=
"glyphicon glyphicon-font"
></span><span
class=
"glyphicon glyphicon-sort-by-alphabet-alt"
></span></a>
<a
id=
"desc"
class=
"btn btn-primary"
href=
"{{url_for('web.
books_list', data=page, sort='zyx
')}}"
><span
class=
"glyphicon glyphicon-font"
></span><span
class=
"glyphicon glyphicon-sort-by-alphabet-alt"
></span></a>
<a
id=
"pub_new"
class=
"btn btn-primary"
href=
"{{url_for('web.
titles_descending')}}"
><span
class=
"glyphicon glyphicon-calendar"
></span><span
class=
"glyphicon glyphicon-sort-by-order"
></a>
<a
id=
"pub_new"
class=
"btn btn-primary"
href=
"{{url_for('web.
books_list', data=page, sort='pubnew')}}"
><span
class=
"glyphicon glyphicon-calendar"
></span><span
class=
"glyphicon glyphicon-sort-by-order"
></span
></a>
<a
id=
"pub_old"
class=
"btn btn-primary"
href=
"{{url_for('web.
titles_descending')}}"
><span
class=
"glyphicon glyphicon-calendar"
></span><span
class=
"glyphicon glyphicon-sort-by-order-alt"
></a>
<a
id=
"pub_old"
class=
"btn btn-primary"
href=
"{{url_for('web.
books_list', data=page, sort='pubold')}}"
><span
class=
"glyphicon glyphicon-calendar"
></span><span
class=
"glyphicon glyphicon-sort-by-order-alt"
></span
></a>
<div
class=
"btn-group character"
role=
"group"
>
<div
class=
"btn-group character"
role=
"group"
>
<a
id=
"no_shelf"
class=
"btn btn-primary"
href=
"{{url_for('web.
titles_descending
')}}"
><span
class=
"glyphicon glyphicon-list"
></span><b>
?
</b></a>
<a
id=
"no_shelf"
class=
"btn btn-primary"
href=
"{{url_for('web.
books_list', data=page, sort='pubold
')}}"
><span
class=
"glyphicon glyphicon-list"
></span><b>
?
</b></a>
<div
id=
"all"
class=
"btn btn-primary"
>
{{_('All')}}
</div>
<div
id=
"all"
class=
"btn btn-primary"
>
{{_('All')}}
</div>
</div>
</div>
</div>
</div>
...
...
cps/templates/layout.html
View file @
9c1b3f13
...
@@ -121,22 +121,10 @@
...
@@ -121,22 +121,10 @@
<ul
class=
"list-unstyled"
id=
"scnd-nav"
intent
in-standard-append=
"nav.navigation"
in-mobile-after=
"#main-nav"
in-mobile-class=
"nav navbar-nav"
>
<ul
class=
"list-unstyled"
id=
"scnd-nav"
intent
in-standard-append=
"nav.navigation"
in-mobile-after=
"#main-nav"
in-mobile-class=
"nav navbar-nav"
>
<li
class=
"nav-head hidden-xs"
>
{{_('Browse')}}
</li>
<li
class=
"nav-head hidden-xs"
>
{{_('Browse')}}
</li>
{% if g.user.check_visibility(1024) %}
<!-- ToDo: eliminate -->
{% if g.user.check_visibility(1024) %}
<!-- ToDo: eliminate -->
<!--li id="nav_sort" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
<span class="glyphicon glyphicon-sort-by-attributes"></span>{{_('Sorted Books')}}
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li id="nav_sort_old" {% if page == 'newest' %}class="active"{% endif %}><a href="{{url_for('web.newest_books')}}">{{_('Sort By')}} {{_('Newest')}}</a></li>
<li id="nav_sort_new" {% if page == 'oldest' %}class="active"{% endif %}><a href="{{url_for('web.oldest_books')}}">{{_('Sort By')}} {{_('Oldest')}}</a></li>
<li id="nav_sort_asc" {% if page == 'a-z' %}class="active"{% endif %}><a href="{{url_for('web.titles_ascending')}}">{{_('Sort By')}} {{_('Title')}} ({{_('Ascending')}})</a></li>
<li id="nav_sort_desc" {% if page == 'z-a' %}class="active"{% endif %}><a href="{{url_for('web.titles_descending')}}">{{_('Sort By')}} {{_('Title')}} ({{_('Descending')}})</a></li>
</ul>
</li-->
{%endif%}
{%endif%}
{% for element in sidebar %}
{% for element in sidebar %}
{% if g.user.check_visibility(element['visibility']) and element['public'] %}
{% if g.user.check_visibility(element['visibility']) and element['public'] %}
<li
id=
"nav_{{element['id']}}"
{%
if
page =
=
element
['
page
']
%}
class=
"active"
{%
endif
%}
><a
href=
"{{url_for(element['link'])}}"
><span
class=
"glyphicon {{element['glyph']}}"
></span>
{{_(element['text'])}}
</a></li>
<li
id=
"nav_{{element['id']}}"
{%
if
page =
=
element
['
page
']
%}
class=
"active"
{%
endif
%}
><a
href=
"{{url_for(element['link']
, data=element['page'], sort='new'
)}}"
><span
class=
"glyphicon {{element['glyph']}}"
></span>
{{_(element['text'])}}
</a></li>
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
...
...
cps/ub.py
View file @
9c1b3f13
...
@@ -107,21 +107,21 @@ def get_sidebar_config(kwargs=[]):
...
@@ -107,21 +107,21 @@ def get_sidebar_config(kwargs=[]):
sidebar
.
append
({
"glyph"
:
"glyphicon-book"
,
"text"
:
_
(
'Recently Added'
),
"link"
:
'web.index'
,
"id"
:
"new"
,
sidebar
.
append
({
"glyph"
:
"glyphicon-book"
,
"text"
:
_
(
'Recently Added'
),
"link"
:
'web.index'
,
"id"
:
"new"
,
"visibility"
:
SIDEBAR_RECENT
,
'public'
:
True
,
"page"
:
"root"
,
"visibility"
:
SIDEBAR_RECENT
,
'public'
:
True
,
"page"
:
"root"
,
"show_text"
:
_
(
'Show recent books'
),
"config_show"
:
True
})
"show_text"
:
_
(
'Show recent books'
),
"config_show"
:
True
})
sidebar
.
append
({
"glyph"
:
"glyphicon-fire"
,
"text"
:
_
(
'Hot Books'
),
"link"
:
'web.
hot_books
'
,
"id"
:
"hot"
,
sidebar
.
append
({
"glyph"
:
"glyphicon-fire"
,
"text"
:
_
(
'Hot Books'
),
"link"
:
'web.
books_list
'
,
"id"
:
"hot"
,
"visibility"
:
SIDEBAR_HOT
,
'public'
:
True
,
"page"
:
"hot"
,
"show_text"
:
_
(
'Show hot books'
),
"visibility"
:
SIDEBAR_HOT
,
'public'
:
True
,
"page"
:
"hot"
,
"show_text"
:
_
(
'Show hot books'
),
"config_show"
:
True
})
"config_show"
:
True
})
sidebar
.
append
(
sidebar
.
append
(
{
"glyph"
:
"glyphicon-star"
,
"text"
:
_
(
'Best rated Books'
),
"link"
:
'web.b
est_rated_books
'
,
"id"
:
"rated"
,
{
"glyph"
:
"glyphicon-star"
,
"text"
:
_
(
'Best rated Books'
),
"link"
:
'web.b
ooks_list
'
,
"id"
:
"rated"
,
"visibility"
:
SIDEBAR_BEST_RATED
,
'public'
:
True
,
"page"
:
"rated"
,
"visibility"
:
SIDEBAR_BEST_RATED
,
'public'
:
True
,
"page"
:
"rated"
,
"show_text"
:
_
(
'Show best rated books'
),
"config_show"
:
True
})
"show_text"
:
_
(
'Show best rated books'
),
"config_show"
:
True
})
sidebar
.
append
({
"glyph"
:
"glyphicon-eye-open"
,
"text"
:
_
(
'Read Books'
),
"link"
:
'web.
read_books
'
,
"id"
:
"read"
,
sidebar
.
append
({
"glyph"
:
"glyphicon-eye-open"
,
"text"
:
_
(
'Read Books'
),
"link"
:
'web.
books_list
'
,
"id"
:
"read"
,
"visibility"
:
SIDEBAR_READ_AND_UNREAD
,
'public'
:
(
not
g
.
user
.
is_anonymous
),
"page"
:
"read"
,
"visibility"
:
SIDEBAR_READ_AND_UNREAD
,
'public'
:
(
not
g
.
user
.
is_anonymous
),
"page"
:
"read"
,
"show_text"
:
_
(
'Show read and unread'
),
"config_show"
:
content
})
"show_text"
:
_
(
'Show read and unread'
),
"config_show"
:
content
})
sidebar
.
append
(
sidebar
.
append
(
{
"glyph"
:
"glyphicon-eye-close"
,
"text"
:
_
(
'Unread Books'
),
"link"
:
'web.
unread_books
'
,
"id"
:
"unread"
,
{
"glyph"
:
"glyphicon-eye-close"
,
"text"
:
_
(
'Unread Books'
),
"link"
:
'web.
books_list
'
,
"id"
:
"unread"
,
"visibility"
:
SIDEBAR_READ_AND_UNREAD
,
'public'
:
(
not
g
.
user
.
is_anonymous
),
"page"
:
"read"
,
"visibility"
:
SIDEBAR_READ_AND_UNREAD
,
'public'
:
(
not
g
.
user
.
is_anonymous
),
"page"
:
"
un
read"
,
"show_text"
:
_
(
'Show unread'
),
"config_show"
:
False
})
"show_text"
:
_
(
'Show unread'
),
"config_show"
:
False
})
sidebar
.
append
({
"glyph"
:
"glyphicon-random"
,
"text"
:
_
(
'Discover'
),
"link"
:
'web.
discover
'
,
"id"
:
"rand"
,
sidebar
.
append
({
"glyph"
:
"glyphicon-random"
,
"text"
:
_
(
'Discover'
),
"link"
:
'web.
books_list
'
,
"id"
:
"rand"
,
"visibility"
:
SIDEBAR_RANDOM
,
'public'
:
True
,
"page"
:
"discover"
,
"visibility"
:
SIDEBAR_RANDOM
,
'public'
:
True
,
"page"
:
"discover"
,
"show_text"
:
_
(
'Show random books'
),
"config_show"
:
True
})
"show_text"
:
_
(
'Show random books'
),
"config_show"
:
True
})
sidebar
.
append
({
"glyph"
:
"glyphicon-inbox"
,
"text"
:
_
(
'Categories'
),
"link"
:
'web.category_list'
,
"id"
:
"cat"
,
sidebar
.
append
({
"glyph"
:
"glyphicon-inbox"
,
"text"
:
_
(
'Categories'
),
"link"
:
'web.category_list'
,
"id"
:
"cat"
,
...
...
cps/web.py
View file @
9c1b3f13
...
@@ -22,10 +22,11 @@
...
@@ -22,10 +22,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from
cps
import
mimetypes
,
global_WorkerThread
,
searched_ids
from
cps
import
mimetypes
,
global_WorkerThread
,
searched_ids
from
flask
import
render_template
,
request
,
redirect
,
send_from_directory
,
make_response
,
g
,
flash
,
abort
,
\
from
flask
import
render_template
,
request
,
redirect
,
send_from_directory
,
make_response
,
g
,
flash
,
abort
,
url_for
url_for
from
werkzeug.exceptions
import
default_exceptions
from
werkzeug.exceptions
import
default_exceptions
import
helper
import
helper
from
helper
import
common_filters
,
get_search_results
,
fill_indexpage
,
speaking_language
,
check_valid_domain
,
\
order_authors
import
os
import
os
from
sqlalchemy.exc
import
IntegrityError
from
sqlalchemy.exc
import
IntegrityError
from
flask_login
import
login_user
,
logout_user
,
login_required
,
current_user
from
flask_login
import
login_user
,
logout_user
,
login_required
,
current_user
...
@@ -36,9 +37,7 @@ from babel import Locale as LC
...
@@ -36,9 +37,7 @@ from babel import Locale as LC
from
babel.dates
import
format_date
from
babel.dates
import
format_date
from
babel.core
import
UnknownLocaleError
from
babel.core
import
UnknownLocaleError
import
base64
import
base64
# from sqlalchemy.sql import *
from
sqlalchemy.sql.expression
import
text
,
func
,
true
,
and_
,
false
,
not_
from
sqlalchemy
import
String
as
SQLString
from
sqlalchemy.sql.expression
import
text
,
func
,
cast
,
true
,
and_
,
false
import
json
import
json
import
datetime
import
datetime
from
iso639
import
languages
as
isoLanguages
from
iso639
import
languages
as
isoLanguages
...
@@ -135,6 +134,7 @@ for ex in default_exceptions:
...
@@ -135,6 +134,7 @@ for ex in default_exceptions:
web
=
Blueprint
(
'web'
,
__name__
)
web
=
Blueprint
(
'web'
,
__name__
)
# ################################### Login logic and rights management ###############################################
@
lm
.
user_loader
@
lm
.
user_loader
def
load_user
(
user_id
):
def
load_user
(
user_id
):
...
@@ -239,89 +239,7 @@ def edit_required(f):
...
@@ -239,89 +239,7 @@ def edit_required(f):
return
inner
return
inner
# ################################### Helper functions ################################################################
# Language and content filters for displaying in the UI
def
common_filters
():
if
current_user
.
filter_language
()
!=
"all"
:
lang_filter
=
db
.
Books
.
languages
.
any
(
db
.
Languages
.
lang_code
==
current_user
.
filter_language
())
else
:
lang_filter
=
true
()
content_rating_filter
=
false
()
if
current_user
.
mature_content
else
\
db
.
Books
.
tags
.
any
(
db
.
Tags
.
name
.
in_
(
config
.
mature_content_tags
()))
return
and_
(
lang_filter
,
~
content_rating_filter
)
# Creates for all stored languages a translated speaking name in the array for the UI
def
speaking_language
(
languages
=
None
):
if
not
languages
:
languages
=
db
.
session
.
query
(
db
.
Languages
)
.
all
()
for
lang
in
languages
:
try
:
cur_l
=
LC
.
parse
(
lang
.
lang_code
)
lang
.
name
=
cur_l
.
get_language_name
(
get_locale
())
except
UnknownLocaleError
:
lang
.
name
=
_
(
isoLanguages
.
get
(
part3
=
lang
.
lang_code
)
.
name
)
return
languages
# checks if domain is in database (including wildcards)
# example SELECT * FROM @TABLE WHERE 'abcdefg' LIKE Name;
# from https://code.luasoftware.com/tutorials/flask/execute-raw-sql-in-flask-sqlalchemy/
def
check_valid_domain
(
domain_text
):
domain_text
=
domain_text
.
split
(
'@'
,
1
)[
-
1
]
.
lower
()
sql
=
"SELECT * FROM registration WHERE :domain LIKE domain;"
result
=
ub
.
session
.
query
(
ub
.
Registration
)
.
from_statement
(
text
(
sql
))
.
params
(
domain
=
domain_text
)
.
all
()
return
len
(
result
)
# Orders all Authors in the list according to authors sort
def
order_authors
(
entry
):
sort_authors
=
entry
.
author_sort
.
split
(
'&'
)
authors_ordered
=
list
()
error
=
False
for
auth
in
sort_authors
:
# ToDo: How to handle not found authorname
result
=
db
.
session
.
query
(
db
.
Authors
)
.
filter
(
db
.
Authors
.
sort
==
auth
.
lstrip
()
.
strip
())
.
first
()
if
not
result
:
error
=
True
break
authors_ordered
.
append
(
result
)
if
not
error
:
entry
.
authors
=
authors_ordered
return
entry
# Fill indexpage with all requested data from database
def
fill_indexpage
(
page
,
database
,
db_filter
,
order
,
*
join
):
if
current_user
.
show_detail_random
():
randm
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
common_filters
())
\
.
order_by
(
func
.
random
())
.
limit
(
config
.
config_random_books
)
else
:
randm
=
false
()
off
=
int
(
int
(
config
.
config_books_per_page
)
*
(
page
-
1
))
pagination
=
Pagination
(
page
,
config
.
config_books_per_page
,
len
(
db
.
session
.
query
(
database
)
.
filter
(
db_filter
)
.
filter
(
common_filters
())
.
all
()))
entries
=
db
.
session
.
query
(
database
)
.
join
(
*
join
,
isouter
=
True
)
.
filter
(
db_filter
)
.
filter
(
common_filters
())
.
\
order_by
(
*
order
)
.
offset
(
off
)
.
limit
(
config
.
config_books_per_page
)
.
all
()
for
book
in
entries
:
book
=
order_authors
(
book
)
return
entries
,
randm
,
pagination
# read search results from calibre-database and return it (function is used for feed and simple search
def
get_search_results
(
term
):
q
=
list
()
authorterms
=
re
.
split
(
"[, ]+"
,
term
)
for
authorterm
in
authorterms
:
q
.
append
(
db
.
Books
.
authors
.
any
(
db
.
Authors
.
name
.
ilike
(
"
%
"
+
authorterm
+
"
%
"
)))
db
.
session
.
connection
()
.
connection
.
connection
.
create_function
(
"lower"
,
1
,
db
.
lcase
)
db
.
Books
.
authors
.
any
(
db
.
Authors
.
name
.
ilike
(
"
%
"
+
term
+
"
%
"
))
return
db
.
session
.
query
(
db
.
Books
)
.
filter
(
common_filters
())
.
filter
(
db
.
or_
(
db
.
Books
.
tags
.
any
(
db
.
Tags
.
name
.
ilike
(
"
%
"
+
term
+
"
%
"
)),
db
.
Books
.
series
.
any
(
db
.
Series
.
name
.
ilike
(
"
%
"
+
term
+
"
%
"
)),
db
.
Books
.
authors
.
any
(
and_
(
*
q
)),
db
.
Books
.
publishers
.
any
(
db
.
Publishers
.
name
.
ilike
(
"
%
"
+
term
+
"
%
"
)),
db
.
Books
.
title
.
ilike
(
"
%
"
+
term
+
"
%
"
)))
.
all
()
# Returns the template for rendering and includes the instance name
# Returns the template for rendering and includes the instance name
...
@@ -343,6 +261,9 @@ def before_request():
...
@@ -343,6 +261,9 @@ def before_request():
return
redirect
(
url_for
(
'admin.basic_configuration'
))
return
redirect
(
url_for
(
'admin.basic_configuration'
))
# ################################### data provider functions #########################################################
@
web
.
route
(
"/ajax/emailstat"
)
@
web
.
route
(
"/ajax/emailstat"
)
@
login_required
@
login_required
def
get_email_status_json
():
def
get_email_status_json
():
...
@@ -354,8 +275,59 @@ def get_email_status_json():
...
@@ -354,8 +275,59 @@ def get_email_status_json():
return
response
return
response
@
web
.
route
(
"/ajax/bookmark/<int:book_id>/<book_format>"
,
methods
=
[
'POST'
])
@
login_required
def
bookmark
(
book_id
,
book_format
):
bookmark_key
=
request
.
form
[
"bookmark"
]
ub
.
session
.
query
(
ub
.
Bookmark
)
.
filter
(
ub
.
and_
(
ub
.
Bookmark
.
user_id
==
int
(
current_user
.
id
),
ub
.
Bookmark
.
book_id
==
book_id
,
ub
.
Bookmark
.
format
==
book_format
))
.
delete
()
if
not
bookmark_key
:
ub
.
session
.
commit
()
return
""
,
204
lbookmark
=
ub
.
Bookmark
(
user_id
=
current_user
.
id
,
book_id
=
book_id
,
format
=
book_format
,
bookmark_key
=
bookmark_key
)
ub
.
session
.
merge
(
lbookmark
)
ub
.
session
.
commit
()
return
""
,
201
@
web
.
route
(
"/ajax/toggleread/<int:book_id>"
,
methods
=
[
'POST'
])
@
login_required
def
toggle_read
(
book_id
):
if
not
config
.
config_read_column
:
book
=
ub
.
session
.
query
(
ub
.
ReadBook
)
.
filter
(
ub
.
and_
(
ub
.
ReadBook
.
user_id
==
int
(
current_user
.
id
),
ub
.
ReadBook
.
book_id
==
book_id
))
.
first
()
if
book
:
book
.
is_read
=
not
book
.
is_read
else
:
readBook
=
ub
.
ReadBook
()
readBook
.
user_id
=
int
(
current_user
.
id
)
readBook
.
book_id
=
book_id
readBook
.
is_read
=
True
book
=
readBook
ub
.
session
.
merge
(
book
)
ub
.
session
.
commit
()
else
:
try
:
db
.
session
.
connection
()
.
connection
.
connection
.
create_function
(
"title_sort"
,
1
,
db
.
title_sort
)
book
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
db
.
Books
.
id
==
book_id
)
.
filter
(
common_filters
())
.
first
()
read_status
=
getattr
(
book
,
'custom_column_'
+
str
(
config
.
config_read_column
))
if
len
(
read_status
):
read_status
[
0
]
.
value
=
not
read_status
[
0
]
.
value
db
.
session
.
commit
()
else
:
cc_class
=
db
.
cc_classes
[
config
.
config_read_column
]
new_cc
=
cc_class
(
value
=
1
,
book
=
book_id
)
db
.
session
.
add
(
new_cc
)
db
.
session
.
commit
()
except
KeyError
:
app
.
logger
.
error
(
u"Custom Column No.
%
d is not exisiting in calibre database"
%
config
.
config_read_column
)
return
""
'''
'''
@web.route("/ajax/getcomic/<int:book_id>/<book_format>/<int:page>")
@web.route("/ajax/getcomic/<int:book_id>/<book_format>/<int:page>")
...
@@ -408,6 +380,7 @@ def get_comic_book(book_id, book_format, page):
...
@@ -408,6 +380,7 @@ def get_comic_book(book_id, book_format, page):
return "", 204
return "", 204
'''
'''
# ################################### Typeahead ##################################################################
@
web
.
route
(
"/get_authors_json"
,
methods
=
[
'GET'
,
'POST'
])
@
web
.
route
(
"/get_authors_json"
,
methods
=
[
'GET'
,
'POST'
])
@
login_required_if_no_ano
@
login_required_if_no_ano
...
@@ -491,6 +464,8 @@ def get_matching_tags():
...
@@ -491,6 +464,8 @@ def get_matching_tags():
return
json_dumps
return
json_dumps
# ################################### View Books list ##################################################################
@
web
.
route
(
"/"
,
defaults
=
{
'page'
:
1
})
@
web
.
route
(
"/"
,
defaults
=
{
'page'
:
1
})
@
web
.
route
(
'/page/<int:page>'
)
@
web
.
route
(
'/page/<int:page>'
)
@
login_required_if_no_ano
@
login_required_if_no_ano
...
@@ -500,49 +475,48 @@ def index(page):
...
@@ -500,49 +475,48 @@ def index(page):
title
=
_
(
u"Recently Added Books"
),
page
=
"root"
)
title
=
_
(
u"Recently Added Books"
),
page
=
"root"
)
@
web
.
route
(
'/books/newest'
,
defaults
=
{
'page'
:
1
})
@
web
.
route
(
'/<data>/<sort>'
,
defaults
=
{
'page'
:
1
})
@
web
.
route
(
'/books/newest/page/<int:page>'
)
@
web
.
route
(
'/<data>/<sort>/<int:page>'
)
@
login_required_if_no_ano
def
newest_books
(
page
):
entries
,
random
,
pagination
=
fill_indexpage
(
page
,
db
.
Books
,
True
,
[
db
.
Books
.
pubdate
.
desc
()])
return
render_title_template
(
'index.html'
,
random
=
random
,
entries
=
entries
,
pagination
=
pagination
,
title
=
_
(
u"Newest Books"
),
page
=
"newest"
)
@
web
.
route
(
'/books/oldest'
,
defaults
=
{
'page'
:
1
})
@
web
.
route
(
'/books/oldest/page/<int:page>'
)
@
login_required_if_no_ano
def
oldest_books
(
page
):
entries
,
random
,
pagination
=
fill_indexpage
(
page
,
db
.
Books
,
True
,
[
db
.
Books
.
pubdate
])
return
render_title_template
(
'index.html'
,
random
=
random
,
entries
=
entries
,
pagination
=
pagination
,
title
=
_
(
u"Oldest Books"
),
page
=
"oldest"
)
@
web
.
route
(
'/books/a-z'
,
defaults
=
{
'page'
:
1
})
@
web
.
route
(
'/books/a-z/page/<int:page>'
)
@
login_required_if_no_ano
@
login_required_if_no_ano
def
titles_ascending
(
page
):
def
books_list
(
data
,
sort
,
page
):
entries
,
random
,
pagination
=
fill_indexpage
(
page
,
db
.
Books
,
True
,
[
db
.
Books
.
sort
])
order
=
[
db
.
Books
.
timestamp
.
desc
()]
return
render_title_template
(
'index.html'
,
random
=
random
,
entries
=
entries
,
pagination
=
pagination
,
if
sort
==
'pubnew'
:
title
=
_
(
u"Books (A-Z)"
),
page
=
"a-z"
)
order
=
[
db
.
Books
.
pubdate
.
desc
()]
if
sort
==
'pubold'
:
order
=
[
db
.
Books
.
pubdate
]
@
web
.
route
(
'/books/z-a'
,
defaults
=
{
'page'
:
1
})
if
sort
==
'abc'
:
@
web
.
route
(
'/books/z-a/page/<int:page>'
)
[
db
.
Books
.
sort
]
@
login_required_if_no_ano
if
sort
==
'zyx'
:
def
titles_descending
(
page
):
[
db
.
Books
.
sort
.
desc
()]
entries
,
random
,
pagination
=
fill_indexpage
(
page
,
db
.
Books
,
True
,
[
db
.
Books
.
sort
.
desc
()])
if
sort
==
'new'
:
order
=
[
db
.
Books
.
timestamp
.
desc
()]
if
sort
==
'old'
:
order
=
[
db
.
Books
.
timestamp
]
if
data
==
"rated"
:
if
current_user
.
check_visibility
(
ub
.
SIDEBAR_BEST_RATED
):
entries
,
random
,
pagination
=
fill_indexpage
(
page
,
db
.
Books
,
db
.
Books
.
ratings
.
any
(
db
.
Ratings
.
rating
>
9
),
order
)
return
render_title_template
(
'index.html'
,
random
=
random
,
entries
=
entries
,
pagination
=
pagination
,
return
render_title_template
(
'index.html'
,
random
=
random
,
entries
=
entries
,
pagination
=
pagination
,
title
=
_
(
u"Books (Z-A)"
),
page
=
"z-a"
)
title
=
_
(
u"Best rated books"
),
page
=
"rated"
)
else
:
abort
(
404
)
@
web
.
route
(
"/hot"
,
defaults
=
{
'page'
:
1
})
elif
data
==
"discover"
:
@
web
.
route
(
'/hot/page/<int:page>'
)
if
current_user
.
check_visibility
(
ub
.
SIDEBAR_RANDOM
):
@
login_required_if_no_ano
entries
,
__
,
pagination
=
fill_indexpage
(
page
,
db
.
Books
,
True
,
[
func
.
randomblob
(
2
)])
def
hot_books
(
page
):
pagination
=
Pagination
(
1
,
config
.
config_books_per_page
,
config
.
config_books_per_page
)
return
render_title_template
(
'discover.html'
,
entries
=
entries
,
pagination
=
pagination
,
title
=
_
(
u"Random Books"
),
page
=
"discover"
)
else
:
abort
(
404
)
elif
data
==
"unread"
:
return
render_read_books
(
page
,
False
,
order
=
order
)
elif
data
==
"read"
:
return
render_read_books
(
page
,
True
,
order
=
order
)
elif
data
==
"hot"
:
if
current_user
.
check_visibility
(
ub
.
SIDEBAR_HOT
):
if
current_user
.
check_visibility
(
ub
.
SIDEBAR_HOT
):
if
current_user
.
show_detail_random
():
if
current_user
.
show_detail_random
():
random
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
common_filters
())
\
random
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
common_filters
())
\
.
order_by
(
func
.
random
())
.
limit
(
config
.
config_random_books
)
.
order_by
(
func
.
random
())
.
limit
(
config
.
config_random_books
)
else
:
else
:
random
=
false
()
random
=
false
()
...
@@ -552,7 +526,8 @@ def hot_books(page):
...
@@ -552,7 +526,8 @@ def hot_books(page):
hot_books
=
all_books
.
offset
(
off
)
.
limit
(
config
.
config_books_per_page
)
hot_books
=
all_books
.
offset
(
off
)
.
limit
(
config
.
config_books_per_page
)
entries
=
list
()
entries
=
list
()
for
book
in
hot_books
:
for
book
in
hot_books
:
downloadBook
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
common_filters
())
.
filter
(
db
.
Books
.
id
==
book
.
Downloads
.
book_id
)
.
first
()
downloadBook
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
common_filters
())
.
filter
(
db
.
Books
.
id
==
book
.
Downloads
.
book_id
)
.
first
()
if
downloadBook
:
if
downloadBook
:
entries
.
append
(
downloadBook
)
entries
.
append
(
downloadBook
)
else
:
else
:
...
@@ -565,6 +540,17 @@ def hot_books(page):
...
@@ -565,6 +540,17 @@ def hot_books(page):
title
=
_
(
u"Hot Books (most downloaded)"
),
page
=
"hot"
)
title
=
_
(
u"Hot Books (most downloaded)"
),
page
=
"hot"
)
else
:
else
:
abort
(
404
)
abort
(
404
)
else
:
entries
,
random
,
pagination
=
fill_indexpage
(
page
,
db
.
Books
,
True
,
order
)
return
render_title_template
(
'index.html'
,
random
=
random
,
entries
=
entries
,
pagination
=
pagination
,
title
=
_
(
u"Books"
),
page
=
"newest"
)
'''
@web.route("/hot", defaults={'page': 1})
@web.route('/hot/page/<int:page>')
@login_required_if_no_ano
def hot_books(page):
@web.route("/rated", defaults={'page': 1})
@web.route("/rated", defaults={'page': 1})
...
@@ -590,7 +576,7 @@ def discover(page):
...
@@ -590,7 +576,7 @@ def discover(page):
return render_title_template('discover.html', entries=entries, pagination=pagination,
return render_title_template('discover.html', entries=entries, pagination=pagination,
title=_(u"Random Books"), page="discover")
title=_(u"Random Books"), page="discover")
else:
else:
abort
(
404
)
abort(404)
'''
@
web
.
route
(
"/author"
)
@
web
.
route
(
"/author"
)
...
@@ -629,7 +615,7 @@ def author(book_id, page):
...
@@ -629,7 +615,7 @@ def author(book_id, page):
try
:
try
:
gc
=
GoodreadsClient
(
config
.
config_goodreads_api_key
,
config
.
config_goodreads_api_secret
)
gc
=
GoodreadsClient
(
config
.
config_goodreads_api_key
,
config
.
config_goodreads_api_secret
)
author_info
=
gc
.
find_author
(
author_name
=
name
)
author_info
=
gc
.
find_author
(
author_name
=
name
)
other_books
=
get_unique_other_books
(
entries
.
all
(),
author_info
.
books
)
other_books
=
helper
.
get_unique_other_books
(
entries
.
all
(),
author_info
.
books
)
except
Exception
:
except
Exception
:
# Skip goodreads, if site is down/inaccessible
# Skip goodreads, if site is down/inaccessible
app
.
logger
.
error
(
'Goodreads website is down/inaccessible'
)
app
.
logger
.
error
(
'Goodreads website is down/inaccessible'
)
...
@@ -670,28 +656,6 @@ def publisher(book_id, page):
...
@@ -670,28 +656,6 @@ def publisher(book_id, page):
abort
(
404
)
abort
(
404
)
def
get_unique_other_books
(
library_books
,
author_books
):
# Get all identifiers (ISBN, Goodreads, etc) and filter author's books by that list so we show fewer duplicates
# Note: Not all images will be shown, even though they're available on Goodreads.com.
# See https://www.goodreads.com/topic/show/18213769-goodreads-book-images
identifiers
=
reduce
(
lambda
acc
,
book
:
acc
+
map
(
lambda
identifier
:
identifier
.
val
,
book
.
identifiers
),
library_books
,
[])
other_books
=
filter
(
lambda
book
:
book
.
isbn
not
in
identifiers
and
book
.
gid
[
"#text"
]
not
in
identifiers
,
author_books
)
# Fuzzy match book titles
if
feature_support
[
'levenshtein'
]:
library_titles
=
reduce
(
lambda
acc
,
book
:
acc
+
[
book
.
title
],
library_books
,
[])
other_books
=
filter
(
lambda
author_book
:
not
filter
(
lambda
library_book
:
# Remove items in parentheses before comparing
Levenshtein
.
ratio
(
re
.
sub
(
r"\(.*\)"
,
""
,
author_book
.
title
),
library_book
)
>
0.7
,
library_titles
),
other_books
)
return
other_books
@
web
.
route
(
"/series"
)
@
web
.
route
(
"/series"
)
@
login_required_if_no_ano
@
login_required_if_no_ano
def
series_list
():
def
series_list
():
...
@@ -854,136 +818,17 @@ def category(book_id, page):
...
@@ -854,136 +818,17 @@ def category(book_id, page):
abort
(
404
)
abort
(
404
)
@
web
.
route
(
"/ajax/toggleread/<int:book_id>"
,
methods
=
[
'POST'
])
@
login_required
def
toggle_read
(
book_id
):
if
not
config
.
config_read_column
:
book
=
ub
.
session
.
query
(
ub
.
ReadBook
)
.
filter
(
ub
.
and_
(
ub
.
ReadBook
.
user_id
==
int
(
current_user
.
id
),
ub
.
ReadBook
.
book_id
==
book_id
))
.
first
()
if
book
:
book
.
is_read
=
not
book
.
is_read
else
:
readBook
=
ub
.
ReadBook
()
readBook
.
user_id
=
int
(
current_user
.
id
)
readBook
.
book_id
=
book_id
readBook
.
is_read
=
True
book
=
readBook
ub
.
session
.
merge
(
book
)
ub
.
session
.
commit
()
else
:
try
:
db
.
session
.
connection
()
.
connection
.
connection
.
create_function
(
"title_sort"
,
1
,
db
.
title_sort
)
book
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
db
.
Books
.
id
==
book_id
)
.
filter
(
common_filters
())
.
first
()
read_status
=
getattr
(
book
,
'custom_column_'
+
str
(
config
.
config_read_column
))
if
len
(
read_status
):
read_status
[
0
]
.
value
=
not
read_status
[
0
]
.
value
db
.
session
.
commit
()
else
:
cc_class
=
db
.
cc_classes
[
config
.
config_read_column
]
new_cc
=
cc_class
(
value
=
1
,
book
=
book_id
)
db
.
session
.
add
(
new_cc
)
db
.
session
.
commit
()
except
KeyError
:
app
.
logger
.
error
(
u"Custom Column No.
%
d is not exisiting in calibre database"
%
config
.
config_read_column
)
return
""
@
web
.
route
(
"/book/<int:book_id>"
)
@
login_required_if_no_ano
def
show_book
(
book_id
):
entries
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
db
.
Books
.
id
==
book_id
)
.
filter
(
common_filters
())
.
first
()
if
entries
:
for
index
in
range
(
0
,
len
(
entries
.
languages
)):
try
:
entries
.
languages
[
index
]
.
language_name
=
LC
.
parse
(
entries
.
languages
[
index
]
.
lang_code
)
.
get_language_name
(
get_locale
())
except
UnknownLocaleError
:
entries
.
languages
[
index
]
.
language_name
=
_
(
isoLanguages
.
get
(
part3
=
entries
.
languages
[
index
]
.
lang_code
)
.
name
)
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
==
book_id
)
.
all
()
for
entry
in
shelfs
:
book_in_shelfs
.
append
(
entry
.
shelf
)
if
not
current_user
.
is_anonymous
:
if
not
config
.
config_read_column
:
matching_have_read_book
=
ub
.
session
.
query
(
ub
.
ReadBook
)
.
\
filter
(
ub
.
and_
(
ub
.
ReadBook
.
user_id
==
int
(
current_user
.
id
),
ub
.
ReadBook
.
book_id
==
book_id
))
.
all
()
have_read
=
len
(
matching_have_read_book
)
>
0
and
matching_have_read_book
[
0
]
.
is_read
else
:
try
:
matching_have_read_book
=
getattr
(
entries
,
'custom_column_'
+
str
(
config
.
config_read_column
))
have_read
=
len
(
matching_have_read_book
)
>
0
and
matching_have_read_book
[
0
]
.
value
except
KeyError
:
app
.
logger
.
error
(
u"Custom Column No.
%
d is not exisiting in calibre database"
%
config
.
config_read_column
)
have_read
=
None
else
:
have_read
=
None
entries
.
tags
=
sort
(
entries
.
tags
,
key
=
lambda
tag
:
tag
.
name
)
entries
=
order_authors
(
entries
)
kindle_list
=
helper
.
check_send_to_kindle
(
entries
)
reader_list
=
helper
.
check_read_formats
(
entries
)
audioentries
=
[]
for
media_format
in
entries
.
data
:
if
media_format
.
format
.
lower
()
in
EXTENSIONS_AUDIO
:
audioentries
.
append
(
media_format
.
format
.
lower
())
return
render_title_template
(
'detail.html'
,
entry
=
entries
,
audioentries
=
audioentries
,
cc
=
cc
,
is_xhr
=
request
.
is_xhr
,
title
=
entries
.
title
,
books_shelfs
=
book_in_shelfs
,
have_read
=
have_read
,
kindle_list
=
kindle_list
,
reader_list
=
reader_list
,
page
=
"book"
)
else
:
flash
(
_
(
u"Error opening eBook. File does not exist or file is not accessible:"
),
category
=
"error"
)
return
redirect
(
url_for
(
"web.index"
))
@
web
.
route
(
"/ajax/bookmark/<int:book_id>/<book_format>"
,
methods
=
[
'POST'
])
@
login_required
def
bookmark
(
book_id
,
book_format
):
bookmark_key
=
request
.
form
[
"bookmark"
]
ub
.
session
.
query
(
ub
.
Bookmark
)
.
filter
(
ub
.
and_
(
ub
.
Bookmark
.
user_id
==
int
(
current_user
.
id
),
ub
.
Bookmark
.
book_id
==
book_id
,
ub
.
Bookmark
.
format
==
book_format
))
.
delete
()
if
not
bookmark_key
:
ub
.
session
.
commit
()
return
""
,
204
lbookmark
=
ub
.
Bookmark
(
user_id
=
current_user
.
id
,
book_id
=
book_id
,
format
=
book_format
,
bookmark_key
=
bookmark_key
)
ub
.
session
.
merge
(
lbookmark
)
ub
.
session
.
commit
()
return
""
,
201
@
web
.
route
(
"/tasks"
)
@
web
.
route
(
"/tasks"
)
@
login_required
@
login_required
def
get_tasks_status
():
def
get_tasks_status
():
# if current user admin, show all email, otherwise only own emails
# if current user admin, show all email, otherwise only own emails
tasks
=
global_WorkerThread
.
get_taskstatus
()
tasks
=
global_WorkerThread
.
get_taskstatus
()
# UIanswer = copy.deepcopy(answer)
answer
=
helper
.
render_task_status
(
tasks
)
answer
=
helper
.
render_task_status
(
tasks
)
# foreach row format row
return
render_title_template
(
'tasks.html'
,
entries
=
answer
,
title
=
_
(
u"Tasks"
),
page
=
"tasks"
)
return
render_title_template
(
'tasks.html'
,
entries
=
answer
,
title
=
_
(
u"Tasks"
),
page
=
"tasks"
)
# ################################### Search functions ################################################################
@
web
.
route
(
"/search"
,
methods
=
[
"GET"
])
@
web
.
route
(
"/search"
,
methods
=
[
"GET"
])
@
login_required_if_no_ano
@
login_required_if_no_ano
def
search
():
def
search
():
...
@@ -1148,34 +993,7 @@ def advanced_search():
...
@@ -1148,34 +993,7 @@ def advanced_search():
series
=
series
,
title
=
_
(
u"search"
),
cc
=
cc
,
page
=
"advsearch"
)
series
=
series
,
title
=
_
(
u"search"
),
cc
=
cc
,
page
=
"advsearch"
)
@
web
.
route
(
"/cover/<int:book_id>"
)
'''@web.route("/unreadbooks/", defaults={'page': 1})
@
login_required_if_no_ano
def
get_cover
(
book_id
):
book
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
db
.
Books
.
id
==
book_id
)
.
first
()
return
helper
.
get_book_cover
(
book
.
path
)
@
web
.
route
(
"/show/<book_id>/<book_format>"
)
@
login_required_if_no_ano
def
serve_book
(
book_id
,
book_format
):
book_format
=
book_format
.
split
(
"."
)[
0
]
book
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
db
.
Books
.
id
==
book_id
)
.
first
()
data
=
db
.
session
.
query
(
db
.
Data
)
.
filter
(
db
.
Data
.
book
==
book
.
id
)
.
filter
(
db
.
Data
.
format
==
book_format
.
upper
())
\
.
first
()
app
.
logger
.
info
(
'Serving book:
%
s'
,
data
.
name
)
if
config
.
config_use_google_drive
:
headers
=
Headers
()
try
:
headers
[
"Content-Type"
]
=
mimetypes
.
types_map
[
'.'
+
book_format
]
except
KeyError
:
headers
[
"Content-Type"
]
=
"application/octet-stream"
df
=
gdriveutils
.
getFileFromEbooksFolder
(
book
.
path
,
data
.
name
+
"."
+
book_format
)
return
gdriveutils
.
do_gdrive_download
(
df
,
headers
)
else
:
return
send_from_directory
(
os
.
path
.
join
(
config
.
config_calibre_dir
,
book
.
path
),
data
.
name
+
"."
+
book_format
)
@
web
.
route
(
"/unreadbooks/"
,
defaults
=
{
'page'
:
1
})
@web.route("/unreadbooks/<int:page>'")
@web.route("/unreadbooks/<int:page>'")
@login_required_if_no_ano
@login_required_if_no_ano
def unread_books(page):
def unread_books(page):
...
@@ -1186,10 +1004,10 @@ def unread_books(page):
...
@@ -1186,10 +1004,10 @@ def unread_books(page):
@web.route("/readbooks/<int:page>'")
@web.route("/readbooks/<int:page>'")
@login_required_if_no_ano
@login_required_if_no_ano
def read_books(page):
def read_books(page):
return
render_read_books
(
page
,
True
)
return render_read_books(page, True)
'''
def
render_read_books
(
page
,
are_read
,
as_xml
=
False
):
def
render_read_books
(
page
,
are_read
,
as_xml
=
False
,
order
=
[]
):
if
not
config
.
config_read_column
:
if
not
config
.
config_read_column
:
readBooks
=
ub
.
session
.
query
(
ub
.
ReadBook
)
.
filter
(
ub
.
ReadBook
.
user_id
==
int
(
current_user
.
id
))
\
readBooks
=
ub
.
session
.
query
(
ub
.
ReadBook
)
.
filter
(
ub
.
ReadBook
.
user_id
==
int
(
current_user
.
id
))
\
.
filter
(
ub
.
ReadBook
.
is_read
is
True
)
.
all
()
.
filter
(
ub
.
ReadBook
.
is_read
is
True
)
.
all
()
...
@@ -1208,7 +1026,7 @@ def render_read_books(page, are_read, as_xml=False):
...
@@ -1208,7 +1026,7 @@ def render_read_books(page, are_read, as_xml=False):
else
:
else
:
db_filter
=
~
db
.
Books
.
id
.
in_
(
readBookIds
)
db_filter
=
~
db
.
Books
.
id
.
in_
(
readBookIds
)
entries
,
random
,
pagination
=
fill_indexpage
(
page
,
db
.
Books
,
db_filter
,
[
db
.
Books
.
timestamp
.
desc
()]
)
entries
,
random
,
pagination
=
fill_indexpage
(
page
,
db
.
Books
,
db_filter
,
order
)
if
as_xml
:
if
as_xml
:
xml
=
render_title_template
(
'feed.xml'
,
entries
=
entries
,
pagination
=
pagination
)
xml
=
render_title_template
(
'feed.xml'
,
entries
=
entries
,
pagination
=
pagination
)
...
@@ -1218,68 +1036,42 @@ def render_read_books(page, are_read, as_xml=False):
...
@@ -1218,68 +1036,42 @@ def render_read_books(page, are_read, as_xml=False):
else
:
else
:
if
are_read
:
if
are_read
:
name
=
_
(
u'Read Books'
)
+
' ('
+
str
(
len
(
readBookIds
))
+
')'
name
=
_
(
u'Read Books'
)
+
' ('
+
str
(
len
(
readBookIds
))
+
')'
pagename
=
"read"
else
:
else
:
total_books
=
db
.
session
.
query
(
func
.
count
(
db
.
Books
.
id
))
.
scalar
()
total_books
=
db
.
session
.
query
(
func
.
count
(
db
.
Books
.
id
))
.
scalar
()
name
=
_
(
u'Unread Books'
)
+
' ('
+
str
(
total_books
-
len
(
readBookIds
))
+
')'
name
=
_
(
u'Unread Books'
)
+
' ('
+
str
(
total_books
-
len
(
readBookIds
))
+
')'
pagename
=
"unread"
return
render_title_template
(
'index.html'
,
random
=
random
,
entries
=
entries
,
pagination
=
pagination
,
return
render_title_template
(
'index.html'
,
random
=
random
,
entries
=
entries
,
pagination
=
pagination
,
title
=
_
(
name
,
name
=
name
),
page
=
"read"
)
title
=
name
,
page
=
pagename
)
@
web
.
route
(
"/read/<int:book_id>/<book_format>"
)
# ################################### Download/Send ##################################################################
@
web
.
route
(
"/cover/<int:book_id>"
)
@
login_required_if_no_ano
@
login_required_if_no_ano
def
read_book
(
book_id
,
book_format
):
def
get_cover
(
book_id
):
book
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
db
.
Books
.
id
==
book_id
)
.
first
()
book
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
db
.
Books
.
id
==
book_id
)
.
first
()
if
not
book
:
return
helper
.
get_book_cover
(
book
.
path
)
flash
(
_
(
u"Error opening eBook. File does not exist or file is not accessible:"
),
category
=
"error"
)
return
redirect
(
url_for
(
"web.index"
))
# check if book was downloaded before
bookmark
=
None
@
web
.
route
(
"/show/<book_id>/<book_format>"
)
if
current_user
.
is_authenticated
:
@
login_required_if_no_ano
bookmark
=
ub
.
session
.
query
(
ub
.
Bookmark
)
.
filter
(
ub
.
and_
(
ub
.
Bookmark
.
user_id
==
int
(
current_user
.
id
),
def
serve_book
(
book_id
,
book_format
):
ub
.
Bookmark
.
book_id
==
book_id
,
book_format
=
book_format
.
split
(
"."
)[
0
]
ub
.
Bookmark
.
format
==
book_format
.
upper
()))
.
first
()
book
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
db
.
Books
.
id
==
book_id
)
.
first
()
if
book_format
.
lower
()
==
"epub"
:
data
=
db
.
session
.
query
(
db
.
Data
)
.
filter
(
db
.
Data
.
book
==
book
.
id
)
.
filter
(
db
.
Data
.
format
==
book_format
.
upper
())
\
return
render_title_template
(
'read.html'
,
bookid
=
book_id
,
title
=
_
(
u"Read a Book"
),
bookmark
=
bookmark
)
.
first
()
elif
book_format
.
lower
()
==
"pdf"
:
app
.
logger
.
info
(
'Serving book:
%
s'
,
data
.
name
)
return
render_title_template
(
'readpdf.html'
,
pdffile
=
book_id
,
title
=
_
(
u"Read a Book"
))
if
config
.
config_use_google_drive
:
elif
book_format
.
lower
()
==
"txt"
:
headers
=
Headers
()
return
render_title_template
(
'readtxt.html'
,
txtfile
=
book_id
,
title
=
_
(
u"Read a Book"
))
try
:
elif
book_format
.
lower
()
==
"mp3"
:
headers
[
"Content-Type"
]
=
mimetypes
.
types_map
[
'.'
+
book_format
]
entries
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
db
.
Books
.
id
==
book_id
)
.
filter
(
common_filters
())
.
first
()
except
KeyError
:
return
render_title_template
(
'listenmp3.html'
,
mp3file
=
book_id
,
audioformat
=
book_format
.
lower
(),
headers
[
"Content-Type"
]
=
"application/octet-stream"
title
=
_
(
u"Read a Book"
),
entry
=
entries
,
bookmark
=
bookmark
)
df
=
gdriveutils
.
getFileFromEbooksFolder
(
book
.
path
,
data
.
name
+
"."
+
book_format
)
elif
book_format
.
lower
()
==
"m4b"
:
return
gdriveutils
.
do_gdrive_download
(
df
,
headers
)
entries
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
db
.
Books
.
id
==
book_id
)
.
filter
(
common_filters
())
.
first
()
return
render_title_template
(
'listenmp3.html'
,
mp3file
=
book_id
,
audioformat
=
book_format
.
lower
(),
title
=
_
(
u"Read a Book"
),
entry
=
entries
,
bookmark
=
bookmark
)
elif
book_format
.
lower
()
==
"m4a"
:
entries
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
db
.
Books
.
id
==
book_id
)
.
filter
(
common_filters
())
.
first
()
return
render_title_template
(
'listenmp3.html'
,
mp3file
=
book_id
,
audioformat
=
book_format
.
lower
(),
title
=
_
(
u"Read a Book"
),
entry
=
entries
,
bookmark
=
bookmark
)
else
:
book_dir
=
os
.
path
.
join
(
config
.
get_main_dir
,
"cps"
,
"static"
,
str
(
book_id
))
if
not
os
.
path
.
exists
(
book_dir
):
os
.
mkdir
(
book_dir
)
for
fileext
in
[
"cbr"
,
"cbt"
,
"cbz"
]:
if
book_format
.
lower
()
==
fileext
:
all_name
=
str
(
book_id
)
# + "/" + book.data[0].name + "." + fileext
# tmp_file = os.path.join(book_dir, book.data[0].name) + "." + fileext
# if not os.path.exists(all_name):
# cbr_file = os.path.join(config.config_calibre_dir, book.path, book.data[0].name) + "." + fileext
# copyfile(cbr_file, tmp_file)
return
render_title_template
(
'readcbr.html'
,
comicfile
=
all_name
,
title
=
_
(
u"Read a Book"
),
extension
=
fileext
)
'''if feature_support['rar']:
extensionList = ["cbr","cbt","cbz"]
else
:
else
:
extensionList = ["cbt","cbz"]
return
send_from_directory
(
os
.
path
.
join
(
config
.
config_calibre_dir
,
book
.
path
),
data
.
name
+
"."
+
book_format
)
for fileext in extensionList:
if book_format.lower() == fileext:
return render_title_template('readcbr.html', comicfile=book_id,
extension=fileext, title=_(u"Read a Book"), book=book)
flash(_(u"Error opening eBook. File does not exist or file is not accessible."), category="error")
return redirect(url_for("web.index"))'''
@
web
.
route
(
"/download/<int:book_id>/<book_format>"
)
@
web
.
route
(
"/download/<int:book_id>/<book_format>"
)
...
@@ -1317,6 +1109,29 @@ def get_download_link_ext(book_id, book_format, anyname):
...
@@ -1317,6 +1109,29 @@ def get_download_link_ext(book_id, book_format, anyname):
return
get_download_link
(
book_id
,
book_format
)
return
get_download_link
(
book_id
,
book_format
)
@
web
.
route
(
'/send/<int:book_id>/<book_format>/<int:convert>'
)
@
login_required
@
download_required
def
send_to_kindle
(
book_id
,
book_format
,
convert
):
settings
=
ub
.
get_mail_settings
()
if
settings
.
get
(
"mail_server"
,
"mail.example.com"
)
==
"mail.example.com"
:
flash
(
_
(
u"Please configure the SMTP mail settings first..."
),
category
=
"error"
)
elif
current_user
.
kindle_mail
:
result
=
helper
.
send_mail
(
book_id
,
book_format
,
convert
,
current_user
.
kindle_mail
,
config
.
config_calibre_dir
,
current_user
.
nickname
)
if
result
is
None
:
flash
(
_
(
u"Book successfully queued for sending to
%(kindlemail)
s"
,
kindlemail
=
current_user
.
kindle_mail
),
category
=
"success"
)
ub
.
update_download
(
book_id
,
int
(
current_user
.
id
))
else
:
flash
(
_
(
u"There was an error sending this book:
%(res)
s"
,
res
=
result
),
category
=
"error"
)
else
:
flash
(
_
(
u"Please configure your kindle e-mail address first..."
),
category
=
"error"
)
return
redirect
(
request
.
environ
[
"HTTP_REFERER"
])
# ################################### Login Logout ##################################################################
@
web
.
route
(
'/register'
,
methods
=
[
'GET'
,
'POST'
])
@
web
.
route
(
'/register'
,
methods
=
[
'GET'
,
'POST'
])
def
register
():
def
register
():
if
not
config
.
config_public_reg
:
if
not
config
.
config_public_reg
:
...
@@ -1502,26 +1317,7 @@ def token_verified():
...
@@ -1502,26 +1317,7 @@ def token_verified():
return
response
return
response
@
web
.
route
(
'/send/<int:book_id>/<book_format>/<int:convert>'
)
# ################################### Users own configuration #########################################################
@
login_required
@
download_required
def
send_to_kindle
(
book_id
,
book_format
,
convert
):
settings
=
ub
.
get_mail_settings
()
if
settings
.
get
(
"mail_server"
,
"mail.example.com"
)
==
"mail.example.com"
:
flash
(
_
(
u"Please configure the SMTP mail settings first..."
),
category
=
"error"
)
elif
current_user
.
kindle_mail
:
result
=
helper
.
send_mail
(
book_id
,
book_format
,
convert
,
current_user
.
kindle_mail
,
config
.
config_calibre_dir
,
current_user
.
nickname
)
if
result
is
None
:
flash
(
_
(
u"Book successfully queued for sending to
%(kindlemail)
s"
,
kindlemail
=
current_user
.
kindle_mail
),
category
=
"success"
)
ub
.
update_download
(
book_id
,
int
(
current_user
.
id
))
else
:
flash
(
_
(
u"There was an error sending this book:
%(res)
s"
,
res
=
result
),
category
=
"error"
)
else
:
flash
(
_
(
u"Please configure your kindle e-mail address first..."
),
category
=
"error"
)
return
redirect
(
request
.
environ
[
"HTTP_REFERER"
])
@
web
.
route
(
"/me"
,
methods
=
[
"GET"
,
"POST"
])
@
web
.
route
(
"/me"
,
methods
=
[
"GET"
,
"POST"
])
@
login_required
@
login_required
...
@@ -1589,3 +1385,125 @@ def profile():
...
@@ -1589,3 +1385,125 @@ def profile():
name
=
current_user
.
nickname
),
page
=
"me"
,
registered_oauth
=
oauth_check
,
name
=
current_user
.
nickname
),
page
=
"me"
,
registered_oauth
=
oauth_check
,
oauth_status
=
oauth_status
)
oauth_status
=
oauth_status
)
# ###################################Show single book ##################################################################
@
web
.
route
(
"/read/<int:book_id>/<book_format>"
)
@
login_required_if_no_ano
def
read_book
(
book_id
,
book_format
):
book
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
db
.
Books
.
id
==
book_id
)
.
first
()
if
not
book
:
flash
(
_
(
u"Error opening eBook. File does not exist or file is not accessible:"
),
category
=
"error"
)
return
redirect
(
url_for
(
"web.index"
))
# check if book was downloaded before
bookmark
=
None
if
current_user
.
is_authenticated
:
bookmark
=
ub
.
session
.
query
(
ub
.
Bookmark
)
.
filter
(
ub
.
and_
(
ub
.
Bookmark
.
user_id
==
int
(
current_user
.
id
),
ub
.
Bookmark
.
book_id
==
book_id
,
ub
.
Bookmark
.
format
==
book_format
.
upper
()))
.
first
()
if
book_format
.
lower
()
==
"epub"
:
return
render_title_template
(
'read.html'
,
bookid
=
book_id
,
title
=
_
(
u"Read a Book"
),
bookmark
=
bookmark
)
elif
book_format
.
lower
()
==
"pdf"
:
return
render_title_template
(
'readpdf.html'
,
pdffile
=
book_id
,
title
=
_
(
u"Read a Book"
))
elif
book_format
.
lower
()
==
"txt"
:
return
render_title_template
(
'readtxt.html'
,
txtfile
=
book_id
,
title
=
_
(
u"Read a Book"
))
elif
book_format
.
lower
()
==
"mp3"
:
entries
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
db
.
Books
.
id
==
book_id
)
.
filter
(
common_filters
())
.
first
()
return
render_title_template
(
'listenmp3.html'
,
mp3file
=
book_id
,
audioformat
=
book_format
.
lower
(),
title
=
_
(
u"Read a Book"
),
entry
=
entries
,
bookmark
=
bookmark
)
elif
book_format
.
lower
()
==
"m4b"
:
entries
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
db
.
Books
.
id
==
book_id
)
.
filter
(
common_filters
())
.
first
()
return
render_title_template
(
'listenmp3.html'
,
mp3file
=
book_id
,
audioformat
=
book_format
.
lower
(),
title
=
_
(
u"Read a Book"
),
entry
=
entries
,
bookmark
=
bookmark
)
elif
book_format
.
lower
()
==
"m4a"
:
entries
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
db
.
Books
.
id
==
book_id
)
.
filter
(
common_filters
())
.
first
()
return
render_title_template
(
'listenmp3.html'
,
mp3file
=
book_id
,
audioformat
=
book_format
.
lower
(),
title
=
_
(
u"Read a Book"
),
entry
=
entries
,
bookmark
=
bookmark
)
else
:
book_dir
=
os
.
path
.
join
(
config
.
get_main_dir
,
"cps"
,
"static"
,
str
(
book_id
))
if
not
os
.
path
.
exists
(
book_dir
):
os
.
mkdir
(
book_dir
)
for
fileext
in
[
"cbr"
,
"cbt"
,
"cbz"
]:
if
book_format
.
lower
()
==
fileext
:
all_name
=
str
(
book_id
)
# + "/" + book.data[0].name + "." + fileext
# tmp_file = os.path.join(book_dir, book.data[0].name) + "." + fileext
# if not os.path.exists(all_name):
# cbr_file = os.path.join(config.config_calibre_dir, book.path, book.data[0].name) + "." + fileext
# copyfile(cbr_file, tmp_file)
return
render_title_template
(
'readcbr.html'
,
comicfile
=
all_name
,
title
=
_
(
u"Read a Book"
),
extension
=
fileext
)
'''if feature_support['rar']:
extensionList = ["cbr","cbt","cbz"]
else:
extensionList = ["cbt","cbz"]
for fileext in extensionList:
if book_format.lower() == fileext:
return render_title_template('readcbr.html', comicfile=book_id,
extension=fileext, title=_(u"Read a Book"), book=book)
flash(_(u"Error opening eBook. File does not exist or file is not accessible."), category="error")
return redirect(url_for("web.index"))'''
@
web
.
route
(
"/book/<int:book_id>"
)
@
login_required_if_no_ano
def
show_book
(
book_id
):
entries
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
db
.
Books
.
id
==
book_id
)
.
filter
(
common_filters
())
.
first
()
if
entries
:
for
index
in
range
(
0
,
len
(
entries
.
languages
)):
try
:
entries
.
languages
[
index
]
.
language_name
=
LC
.
parse
(
entries
.
languages
[
index
]
.
lang_code
)
.
get_language_name
(
get_locale
())
except
UnknownLocaleError
:
entries
.
languages
[
index
]
.
language_name
=
_
(
isoLanguages
.
get
(
part3
=
entries
.
languages
[
index
]
.
lang_code
)
.
name
)
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
==
book_id
)
.
all
()
for
entry
in
shelfs
:
book_in_shelfs
.
append
(
entry
.
shelf
)
if
not
current_user
.
is_anonymous
:
if
not
config
.
config_read_column
:
matching_have_read_book
=
ub
.
session
.
query
(
ub
.
ReadBook
)
.
\
filter
(
ub
.
and_
(
ub
.
ReadBook
.
user_id
==
int
(
current_user
.
id
),
ub
.
ReadBook
.
book_id
==
book_id
))
.
all
()
have_read
=
len
(
matching_have_read_book
)
>
0
and
matching_have_read_book
[
0
]
.
is_read
else
:
try
:
matching_have_read_book
=
getattr
(
entries
,
'custom_column_'
+
str
(
config
.
config_read_column
))
have_read
=
len
(
matching_have_read_book
)
>
0
and
matching_have_read_book
[
0
]
.
value
except
KeyError
:
app
.
logger
.
error
(
u"Custom Column No.
%
d is not exisiting in calibre database"
%
config
.
config_read_column
)
have_read
=
None
else
:
have_read
=
None
entries
.
tags
=
sort
(
entries
.
tags
,
key
=
lambda
tag
:
tag
.
name
)
entries
=
order_authors
(
entries
)
kindle_list
=
helper
.
check_send_to_kindle
(
entries
)
reader_list
=
helper
.
check_read_formats
(
entries
)
audioentries
=
[]
for
media_format
in
entries
.
data
:
if
media_format
.
format
.
lower
()
in
EXTENSIONS_AUDIO
:
audioentries
.
append
(
media_format
.
format
.
lower
())
return
render_title_template
(
'detail.html'
,
entry
=
entries
,
audioentries
=
audioentries
,
cc
=
cc
,
is_xhr
=
request
.
is_xhr
,
title
=
entries
.
title
,
books_shelfs
=
book_in_shelfs
,
have_read
=
have_read
,
kindle_list
=
kindle_list
,
reader_list
=
reader_list
,
page
=
"book"
)
else
:
flash
(
_
(
u"Error opening eBook. File does not exist or file is not accessible:"
),
category
=
"error"
)
return
redirect
(
url_for
(
"web.index"
))
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment