Skip to content

Commit c8b4e01

Browse files
Ikeltisclaude
andcommitted
Fix Douban cover download failing with HTTP 418
Douban's image CDN (*.doubanio.com) enforces hotlink protection and returns HTTP 418 unless the request carries a douban Referer, so covers fetched via the Douban metadata provider never download. Send `Referer: https://book.douban.com/` when the cover URL points at a doubanio.com host so save_cover_from_url succeeds. Requests to any other host are unaffected. This mirrors how existing Calibre desktop Douban plugins work around the same protection. Refs #913 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 43718d8 commit c8b4e01

1 file changed

Lines changed: 9 additions & 3 deletions

File tree

cps/helper.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
from werkzeug.datastructures import Headers
3232
from werkzeug.security import generate_password_hash
3333
from markupsafe import escape
34-
from urllib.parse import quote
34+
from urllib.parse import quote, urlparse
3535

3636
try:
3737
from . import cw_advocate
@@ -1062,10 +1062,16 @@ def save_cover_from_url(url, book_path):
10621062
img = None
10631063
download_start = time.monotonic()
10641064
try:
1065+
# Douban's image CDN (doubanio.com) enforces hotlink protection and answers
1066+
# with HTTP 418 unless a douban Referer is sent, which makes cover downloads
1067+
# from the Douban metadata provider fail. Send the Referer for those hosts.
1068+
req_headers = None
1069+
if (urlparse(url).hostname or "").endswith("doubanio.com"):
1070+
req_headers = {"Referer": "https://book.douban.com/"}
10651071
if cli_param.allow_localhost:
1066-
img = requests.get(url, timeout=(10, 30), allow_redirects=False, stream=True) # ToDo: Error Handling
1072+
img = requests.get(url, timeout=(10, 30), allow_redirects=False, stream=True, headers=req_headers) # ToDo: Error Handling
10671073
elif use_advocate:
1068-
img = cw_advocate.get(url, timeout=(10, 30), allow_redirects=False, stream=True) # ToDo: Error Handling
1074+
img = cw_advocate.get(url, timeout=(10, 30), allow_redirects=False, stream=True, headers=req_headers) # ToDo: Error Handling
10691075
else:
10701076
log.error("python module advocate is not installed but is needed")
10711077
return False, _("Python module 'advocate' is not installed but is needed for cover uploads")

0 commit comments

Comments
 (0)