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
baf83b2f
Commit
baf83b2f
authored
Mar 16, 2019
by
Ozzieisaacs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactored generating download links
parent
9c1b3f13
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
76 additions
and
75 deletions
+76
-75
helper.py
cps/helper.py
+51
-2
opds.py
cps/opds.py
+5
-22
detail.html
cps/templates/detail.html
+2
-2
feed.xml
cps/templates/feed.xml
+1
-1
json.txt
cps/templates/json.txt
+2
-2
read.html
cps/templates/read.html
+1
-1
shelfdown.html
cps/templates/shelfdown.html
+2
-2
web.py
cps/web.py
+12
-43
No files found.
cps/helper.py
View file @
baf83b2f
...
...
@@ -19,7 +19,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from
cps
import
config
,
global_WorkerThread
,
get_locale
,
db
from
cps
import
config
,
global_WorkerThread
,
get_locale
,
db
,
mimetypes
from
flask
import
current_app
as
app
from
tempfile
import
gettempdir
import
sys
...
...
@@ -40,6 +40,7 @@ import requests
from
sqlalchemy.sql.expression
import
true
,
and_
,
false
,
text
,
func
from
iso639
import
languages
as
isoLanguages
from
pagination
import
Pagination
from
werkzeug.datastructures
import
Headers
try
:
import
gdriveutils
as
gd
...
...
@@ -49,12 +50,23 @@ import random
from
subproc_wrapper
import
process_open
import
ub
try
:
from
urllib.parse
import
quote
except
ImportError
:
from
urllib
import
quote
try
:
import
unidecode
use_unidecode
=
True
except
ImportError
:
use_unidecode
=
False
try
:
import
Levenshtein
use_levenshtein
=
True
except
ImportError
:
use_levenshtein
=
False
def
update_download
(
book_id
,
user_id
):
check
=
ub
.
session
.
query
(
ub
.
Downloads
)
.
filter
(
ub
.
Downloads
.
user_id
==
user_id
)
.
filter
(
ub
.
Downloads
.
book_id
==
...
...
@@ -660,7 +672,7 @@ def get_unique_other_books(library_books, author_books):
author_books
)
# Fuzzy match book titles
if
feature_support
[
'levenshtein'
]
:
if
use_levenshtein
:
library_titles
=
reduce
(
lambda
acc
,
book
:
acc
+
[
book
.
title
],
library_books
,
[])
other_books
=
filter
(
lambda
author_book
:
not
filter
(
lambda
library_book
:
...
...
@@ -670,3 +682,40 @@ def get_unique_other_books(library_books, author_books):
),
other_books
)
return
other_books
def
get_cc_columns
():
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
return
cc
def
get_download_link
(
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
()
if
data
:
# collect downloaded books only for registered user and not for anonymous user
if
current_user
.
is_authenticated
:
ub
.
update_download
(
book_id
,
int
(
current_user
.
id
))
file_name
=
book
.
title
if
len
(
book
.
authors
)
>
0
:
file_name
=
book
.
authors
[
0
]
.
name
+
'_'
+
file_name
file_name
=
get_valid_filename
(
file_name
)
headers
=
Headers
()
try
:
headers
[
"Content-Type"
]
=
mimetypes
.
types_map
[
'.'
+
book_format
]
except
KeyError
:
headers
[
"Content-Type"
]
=
"application/octet-stream"
headers
[
"Content-Disposition"
]
=
"attachment; filename*=UTF-8''
%
s.
%
s"
%
(
quote
(
file_name
.
encode
(
'utf-8'
)),
book_format
)
return
do_download_file
(
book
,
book_format
,
data
,
headers
)
else
:
abort
(
404
)
cps/opds.py
View file @
baf83b2f
...
...
@@ -22,7 +22,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# opds routing functions
from
cps
import
config
,
mimetypes
,
app
,
db
from
cps
import
config
,
db
from
flask
import
request
,
render_template
,
Response
,
g
,
make_response
from
pagination
import
Pagination
from
flask
import
Blueprint
...
...
@@ -34,7 +34,6 @@ from web import login_required_if_no_ano, common_filters, get_search_results, re
from
sqlalchemy.sql.expression
import
func
,
text
import
helper
from
werkzeug.security
import
check_password_hash
from
werkzeug.datastructures
import
Headers
from
helper
import
fill_indexpage
import
sys
...
...
@@ -58,7 +57,7 @@ def requires_basic_auth_if_no_ano(f):
return
decorated
@
opds
.
route
(
"/opds"
)
@
opds
.
route
(
"/opds
/
"
)
@
requires_basic_auth_if_no_ano
def
feed_index
():
return
render_xml_template
(
'index.xml'
)
...
...
@@ -258,25 +257,9 @@ def feed_shelf(book_id):
@
opds
.
route
(
"/opds/download/<book_id>/<book_format>/"
)
@
requires_basic_auth_if_no_ano
@
download_required
def
get_opds_download_link
(
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
(
data
.
name
)
if
current_user
.
is_authenticated
:
ub
.
update_download
(
book_id
,
int
(
current_user
.
id
))
file_name
=
book
.
title
if
len
(
book
.
authors
)
>
0
:
file_name
=
book
.
authors
[
0
]
.
name
+
'_'
+
file_name
file_name
=
helper
.
get_valid_filename
(
file_name
)
headers
=
Headers
()
headers
[
"Content-Disposition"
]
=
"attachment; filename*=UTF-8''
%
s.
%
s"
%
(
quote
(
file_name
.
encode
(
'utf8'
)),
book_format
)
try
:
headers
[
"Content-Type"
]
=
mimetypes
.
types_map
[
'.'
+
book_format
]
except
KeyError
:
headers
[
"Content-Type"
]
=
"application/octet-stream"
return
helper
.
do_download_file
(
book
,
book_format
,
data
,
headers
)
def
opds_download_link
(
book_id
,
book_format
):
return
helper
.
get_download_link
(
book_id
,
book_format
)
@
opds
.
route
(
"/ajax/book/<string:uuid>"
)
@
requires_basic_auth_if_no_ano
...
...
cps/templates/detail.html
View file @
baf83b2f
...
...
@@ -22,7 +22,7 @@
{{_('Download')}} :
</button>
{% for format in entry.data %}
<a
href=
"{{ url_for('web.
get_download_link_ext
', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}"
id=
"btnGroupDrop1{{format.format|lower}}"
class=
"btn btn-primary"
role=
"button"
>
<a
href=
"{{ url_for('web.
download_link
', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}"
id=
"btnGroupDrop1{{format.format|lower}}"
class=
"btn btn-primary"
role=
"button"
>
<span
class=
"glyphicon glyphicon-download"
></span>
{{format.format}} ({{ format.uncompressed_size|filesizeformat }})
</a>
{% endfor %}
...
...
@@ -33,7 +33,7 @@
</button>
<ul
class=
"dropdown-menu"
aria-labelledby=
"btnGroupDrop1"
>
{% for format in entry.data %}
<li><a
href=
"{{ url_for('web.
get_download_link_ext
', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}"
>
{{format.format}} ({{ format.uncompressed_size|filesizeformat }})
</a></li>
<li><a
href=
"{{ url_for('web.
download_link
', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}"
>
{{format.format}} ({{ format.uncompressed_size|filesizeformat }})
</a></li>
{% endfor %}
</ul>
{% endif %}
...
...
cps/templates/feed.xml
View file @
baf83b2f
...
...
@@ -65,7 +65,7 @@
<link
type=
"image/jpeg"
href=
"{{url_for('opds.feed_get_cover', book_id=entry.id)}}"
rel=
"http://opds-spec.org/image/thumbnail"
/>
{% endif %}
{% for format in entry.data %}
<link
rel=
"http://opds-spec.org/acquisition"
href=
"{{ url_for('
opds.get_opds_
download_link', book_id=entry.id, book_format=format.format|lower)}}"
<link
rel=
"http://opds-spec.org/acquisition"
href=
"{{ url_for('
web.
download_link', book_id=entry.id, book_format=format.format|lower)}}"
length=
"{{format.uncompressed_size}}"
mtime=
"{{entry.atom_timestamp}}"
type=
"{{format.format|lower|mimetype}}"
/>
{% endfor %}
</entry>
...
...
cps/templates/json.txt
View file @
baf83b2f
...
...
@@ -36,7 +36,7 @@
"timestamp": "{{entry.timestamp}}",
"thumbnail": "{{url_for('opds.feed_get_cover', book_id=entry.id)}}",
"main_format": {
"{{entry.data[0].format|lower}}": "{{ url_for('
opds.get_opds_
download_link', book_id=entry.id, book_format=entry.data[0].format|lower)}}"
"{{entry.data[0].format|lower}}": "{{ url_for('
web.
download_link', book_id=entry.id, book_format=entry.data[0].format|lower)}}"
},
"rating":{% if entry.ratings.__len__() > 0 %} "{{entry.ratings[0].rating}}.0"{% else %}0.0{% endif %},
"authors": [
...
...
@@ -47,7 +47,7 @@
"other_formats": {
{% if entry.data.__len__() > 1 %}
{% for format in entry.data[1:] %}
"{{format.format|lower}}": "{{ url_for('
opds.get_opds_
download_link', book_id=entry.id, book_format=format.format|lower)}}"{% if not loop.last %},{% endif %}
"{{format.format|lower}}": "{{ url_for('
web.
download_link', book_id=entry.id, book_format=format.format|lower)}}"{% if not loop.last %},{% endif %}
{% endfor %}
{% endif %} },
"title_sort": "{{entry.sort}}"
...
...
cps/templates/read.html
View file @
baf83b2f
...
...
@@ -84,7 +84,7 @@
filePath
:
"{{ url_for('static', filename='js/libs/') }}"
,
cssPath
:
"{{ url_for('static', filename='css/') }}"
,
bookmarkUrl
:
"{{ url_for('web.bookmark', book_id=bookid, book_format='EPUB') }}"
,
bookUrl
:
"{{ url_for('web.
get_download_link_ext
', book_id=bookid, book_format='epub', anyname='file.epub') }}"
,
bookUrl
:
"{{ url_for('web.
download_link
', book_id=bookid, book_format='epub', anyname='file.epub') }}"
,
bookmark
:
"{{ bookmark.bookmark_key if bookmark != None }}"
,
useBookmarks
:
"{{ g.user.is_authenticated | tojson }}"
};
...
...
cps/templates/shelfdown.html
View file @
baf83b2f
...
...
@@ -53,7 +53,7 @@
{% if entry.data|length
<
2
%}
{%
for
format
in
entry
.
data
%}
<
a
href=
"{{ url_for('web.
get_download_link_ext
', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}"
id=
"btnGroupDrop1{{format.format|lower}}"
class=
"btn btn-primary"
role=
"button"
>
<
a
href=
"{{ url_for('web.
download_link
', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}"
id=
"btnGroupDrop1{{format.format|lower}}"
class=
"btn btn-primary"
role=
"button"
>
<span
class=
"glyphicon glyphicon-download"
></span>
{{format.format}} ({{ format.uncompressed_size|filesizeformat }})
</a>
{% endfor %}
...
...
@@ -64,7 +64,7 @@
</button>
<ul
class=
"dropdown-menu"
aria-labelledby=
"btnGroupDrop1"
>
{% for format in entry.data %}
<li><a
href=
"{{ url_for('
get_download_link_ext
', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}"
>
{{format.format}} ({{ format.uncompressed_size|filesizeformat }})
</a></li>
<li><a
href=
"{{ url_for('
web.download_link
', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}"
>
{{format.format}} ({{ format.uncompressed_size|filesizeformat }})
</a></li>
{% endfor %}
</ul>
{% endif %}
...
...
cps/web.py
View file @
baf83b2f
...
...
@@ -37,7 +37,7 @@ from babel import Locale as LC
from
babel.dates
import
format_date
from
babel.core
import
UnknownLocaleError
import
base64
from
sqlalchemy.sql.expression
import
text
,
func
,
true
,
and_
,
false
,
not_
from
sqlalchemy.sql.expression
import
text
,
func
,
true
,
false
,
not_
import
json
import
datetime
from
iso639
import
languages
as
isoLanguages
...
...
@@ -63,7 +63,7 @@ except ImportError:
feature_support
[
'ldap'
]
=
False
try
:
from
googleapiclient.errors
import
HttpError
from
googleapiclient.errors
import
HttpError
t
except
ImportError
:
pass
...
...
@@ -73,12 +73,6 @@ try:
except
ImportError
:
feature_support
[
'goodreads'
]
=
False
try
:
import
Levenshtein
feature_support
[
'levenshtein'
]
=
True
except
ImportError
:
feature_support
[
'levenshtein'
]
=
False
try
:
from
functools
import
reduce
,
wraps
except
ImportError
:
...
...
@@ -110,7 +104,7 @@ EXTENSIONS_UPLOAD = {'txt', 'pdf', 'epub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz',
'fb2'
,
'html'
,
'rtf'
,
'odt'
,
'mp3'
,
'm4a'
,
'm4b'
}
'''EXTENSIONS_READER = set(['txt', 'pdf', 'epub', 'zip', 'cbz', 'tar', 'cbt'] +
'''EXTENSIONS_READER = set(['txt', 'pdf', 'epub', 'zip', 'cbz', 'tar', 'cbt'] +
(['rar','cbr'] if feature_support['rar'] else []))'''
...
...
@@ -848,7 +842,8 @@ def search():
@
login_required_if_no_ano
def
advanced_search
():
# Build custom columns names
tmpcc
=
db
.
session
.
query
(
db
.
Custom_Columns
)
.
filter
(
db
.
Custom_Columns
.
datatype
.
notin_
(
db
.
cc_exceptions
))
.
all
()
cc
=
helper
.
get_cc_columns
()
'''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:
...
...
@@ -856,7 +851,7 @@ def advanced_search():
if r.match(col.label):
cc.append(col)
else:
cc
=
tmpcc
cc = tmpcc
'''
db
.
session
.
connection
()
.
connection
.
connection
.
create_function
(
"lower"
,
1
,
db
.
lcase
)
q
=
db
.
session
.
query
(
db
.
Books
)
...
...
@@ -1074,39 +1069,12 @@ def serve_book(book_id, book_format):
return
send_from_directory
(
os
.
path
.
join
(
config
.
config_calibre_dir
,
book
.
path
),
data
.
name
+
"."
+
book_format
)
@
web
.
route
(
"/download/<int:book_id>/<book_format>"
)
@
login_required_if_no_ano
@
download_required
def
get_download_link
(
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
()
if
data
:
# collect downloaded books only for registered user and not for anonymous user
if
current_user
.
is_authenticated
:
ub
.
update_download
(
book_id
,
int
(
current_user
.
id
))
file_name
=
book
.
title
if
len
(
book
.
authors
)
>
0
:
file_name
=
book
.
authors
[
0
]
.
name
+
'_'
+
file_name
file_name
=
helper
.
get_valid_filename
(
file_name
)
headers
=
Headers
()
try
:
headers
[
"Content-Type"
]
=
mimetypes
.
types_map
[
'.'
+
book_format
]
except
KeyError
:
headers
[
"Content-Type"
]
=
"application/octet-stream"
headers
[
"Content-Disposition"
]
=
"attachment; filename*=UTF-8''
%
s.
%
s"
%
(
quote
(
file_name
.
encode
(
'utf-8'
)),
book_format
)
return
helper
.
do_download_file
(
book
,
book_format
,
data
,
headers
)
else
:
abort
(
404
)
@
web
.
route
(
"/download/<int:book_id>/<book_format>"
,
defaults
=
{
'anyname'
:
'None'
})
@
web
.
route
(
"/download/<int:book_id>/<book_format>/<anyname>"
)
@
login_required_if_no_ano
@
download_required
def
get_download_link_ext
(
book_id
,
book_format
,
anyname
):
return
get_download_link
(
book_id
,
book_format
)
def
download_link
(
book_id
,
book_format
,
anyname
):
return
helper
.
get_download_link
(
book_id
,
book_format
)
@
web
.
route
(
'/send/<int:book_id>/<book_format>/<int:convert>'
)
...
...
@@ -1457,7 +1425,8 @@ def show_book(book_id):
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
()
cc
=
helper
.
get_cc_columns
()
'''tmpcc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
if config.config_columns_to_ignore:
cc = []
...
...
@@ -1466,7 +1435,7 @@ def show_book(book_id):
if r.match(col.label):
cc.append(col)
else:
cc
=
tmpcc
cc = tmpcc
'''
book_in_shelfs
=
[]
shelfs
=
ub
.
session
.
query
(
ub
.
BookShelf
)
.
filter
(
ub
.
BookShelf
.
book_id
==
book_id
)
.
all
()
for
entry
in
shelfs
:
...
...
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