Skip to content

Commit 646544b

Browse files
Merge main into auto-hardcover-id - sync with latest changes and resolve conflicts
2 parents 378b2fa + 2206341 commit 646544b

43 files changed

Lines changed: 5706 additions & 646 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CONTRIBUTORS

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ Copyright (C) 2018-2026 Calibre-Web contributors
1111
Copyright (C) 2024-2026 Calibre-Web Automated contributors
1212
# Upstream Contributors (janeczku/calibre-web)
1313

14-
- OzzieIsaacs (anon) (2778 commits)
15-
- Ozzie Isaacs (anon) (266 commits)
14+
- OzzieIsaacs (anon) (2788 commits)
15+
- Ozzie Isaacs (anon) (267 commits)
1616
- cbartondock (96 commits)
1717
- idalin (69 commits)
1818
- cervinko (68 commits)
@@ -41,6 +41,7 @@ Copyright (C) 2024-2026 Calibre-Web Automated contributors
4141
- mapi68 (15 commits)
4242
- ok11 (13 commits)
4343
- pwr (13 commits)
44+
- webysther (13 commits)
4445
- Kyosfonica (11 commits)
4546
- otapi (11 commits)
4647
- andy29485 (10 commits)
@@ -84,7 +85,6 @@ Copyright (C) 2024-2026 Calibre-Web Automated contributors
8485
- Petipopotam (4 commits)
8586
- stfrbrntyu (4 commits)
8687
- trasba (4 commits)
87-
- webysther (4 commits)
8888
- wildthyme (4 commits)
8989
- acciobugs (3 commits)
9090
- aliceout (3 commits)
@@ -196,6 +196,7 @@ Copyright (C) 2024-2026 Calibre-Web Automated contributors
196196
- dotlambda (1 commits)
197197
- ducbachvan (1 commits)
198198
- Dunrar (1 commits)
199+
- EdouardRouch (1 commits)
199200
- Efreak (1 commits)
200201
- elelay (1 commits)
201202
- elfcan (1 commits)
@@ -288,6 +289,7 @@ Copyright (C) 2024-2026 Calibre-Web Automated contributors
288289
- szepix (1 commits)
289290
- theopsall (1 commits)
290291
- Thijxx (1 commits)
292+
- tomchiverton (1 commits)
291293
- tomjmul (1 commits)
292294
- vagra (1 commits)
293295
- viljasenville (1 commits)
@@ -312,7 +314,7 @@ Copyright (C) 2024-2026 Calibre-Web Automated contributors
312314
- zhiyue (1 commits)
313315
# Fork Contributors (crocodilestick/calibre-web-automated)
314316

315-
- crocodilestick (900 commits)
317+
- crocodilestick (941 commits)
316318
- jmarmstrong1207 (73 commits)
317319
- demitrix (30 commits)
318320
- sirwolfgang (29 commits)
@@ -326,6 +328,7 @@ Copyright (C) 2024-2026 Calibre-Web Automated contributors
326328
- alva-seal (6 commits)
327329
- smevawala (5 commits)
328330
- Aymendje (4 commits)
331+
- ManuelDrescher (4 commits)
329332
- opswhisperer (4 commits)
330333
- alexantao (3 commits)
331334
- Calychas (3 commits)
@@ -334,12 +337,14 @@ Copyright (C) 2024-2026 Calibre-Web Automated contributors
334337
- PulsarFTW (3 commits)
335338
- stewie83 (3 commits)
336339
- zikasak (3 commits)
340+
- aaronpowell (2 commits)
341+
- BrachiumX (2 commits)
337342
- chad3814 (2 commits)
338343
- coissac (2 commits)
339344
- FennyFatal (2 commits)
340345
- itsmarcy (2 commits)
341346
- JamesRy96 (2 commits)
342-
- ManuelDrescher (2 commits)
347+
- Olen (2 commits)
343348
- sethvoltz (2 commits)
344349
- Strubbl (2 commits)
345350
- tecosaur (2 commits)
@@ -364,6 +369,7 @@ Copyright (C) 2024-2026 Calibre-Web Automated contributors
364369
- emmanuel-ferdman (1 commits)
365370
- FilipMakowski (1 commits)
366371
- Flying-Tom (1 commits)
372+
- galeksandrp (1 commits)
367373
- google-labs-jules[bot] (1 commits)
368374
- gx1400 (1 commits)
369375
- halkeye (1 commits)
@@ -378,6 +384,7 @@ Copyright (C) 2024-2026 Calibre-Web Automated contributors
378384
- jeffonthemove (1 commits)
379385
- jspiers (1 commits)
380386
- kevpam (1 commits)
387+
- KucharczykL (1 commits)
381388
- lazyusername (1 commits)
382389
- Lee Nave (anon) (1 commits)
383390
- marauder37 (1 commits)
@@ -388,15 +395,16 @@ Copyright (C) 2024-2026 Calibre-Web Automated contributors
388395
- n00b42 (1 commits)
389396
- Nementon (1 commits)
390397
- NotaInutilis (1 commits)
391-
- Olen (1 commits)
392398
- r0b2g1t (1 commits)
393399
- rjaakke (1 commits)
394400
- robinwo (1 commits)
395401
- Rustymage (1 commits)
402+
- Seth Milliken (anon) (1 commits)
396403
- smathev (1 commits)
397404
- spezzino (1 commits)
398405
- stadler-pascal (1 commits)
399406
- stefanop1 (1 commits)
407+
- thetorminal (1 commits)
400408
- tmacphail (1 commits)
401409
- tomried (1 commits)
402410
- Turmaxx (1 commits)

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,14 @@ Calibre-Web Automated aims to be an all-in-one solution, combining the modern li
4646

4747
## _Affiliated Projects_ 👬
4848

49-
### Calibre-Web Automated Book Downloader
49+
### Shelfmark: Book Downloader
5050

5151
- An intuitive web interface for searching and requesting book downloads, designed to work seamlessly with Calibre-Web-Automated. This project streamlines the process of downloading books and preparing them for integration into your Calibre library
5252

53-
[<img src="https://raw.githubusercontent.com/vadret/android/master/assets/get-github.png" alt="Get it on GitHub" height="80">](https://github.com/calibrain/calibre-web-automated-book-downloader)
53+
> [!IMPORTANT]
54+
> CWA does not approve of or support piracy of copyrighted materials and is not responsible for user behaviour
55+
56+
[<img src="https://raw.githubusercontent.com/vadret/android/master/assets/get-github.png" alt="Get it on GitHub" height="80">](https://github.com/calibrain/shelfmark)
5457

5558
___
5659

@@ -142,7 +145,7 @@ This tells CWA to avoid enabling WAL on the Calibre `metadata.db` and the `app.d
142145
- Using the information provided in the Calibre eBook-converter documentation on which formats convert best into epubs, CWA is able to determine from downloads containing multiple eBook formats, which format will convert most optimally, ignoring the other formats to ensure the **best possible quality** and no **duplicate imports** -->
143146

144147
#### **Automatic Conversion Service** 🔃
145-
- On by default though can be toggled of in the CWA Settings page, with EPUB as the default target format
148+
- On by default though can be toggled off in the CWA Settings page, with EPUB as the default target format
146149
- _Available target formats include:_ **EPUB**, **MOBI**, **AZW3**, **KEPUB** & **PDF**
147150
- Upon detecting new files in the Ingest Directory, if any of the files are in formats the user has configured CWA to auto-convert to the current target format,
148151
- The following **28 file types are currently supported:**

cps/__init__.py

Lines changed: 114 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -244,35 +244,125 @@ def create_app():
244244
# Ensure a valid calibre_db session exists before handling each request
245245
@app.before_request
246246
def _cwa_ensure_db_session():
247+
from flask import g, request
247248
from .cw_login import current_user
249+
from sqlalchemy import or_
248250
import time
249251

252+
if config.config_allow_reverse_proxy_header_login:
253+
"""
254+
Load user from reverse proxy authentication header if configured.
255+
Sets g.flask_httpauth_user early so that current_user proxy resolves correctly
256+
for user-specific settings like theme preferences.
257+
258+
This must run before any blueprint before_request handlers that access current_user.
259+
"""
260+
261+
from . import usermanagement
262+
user = usermanagement.load_user_from_reverse_proxy_header(request)
263+
if user:
264+
g.flask_httpauth_user = user
265+
else:
266+
# Explicitly set to None to indicate we checked but found nothing
267+
g.flask_httpauth_user = None
268+
250269
if current_user.is_authenticated:
251-
g.magic_shelves_access = ub.session.query(ub.MagicShelf).filter(ub.MagicShelf.user_id == current_user.id).all()
252-
253-
# Magic Shelf Count Caching
254-
if 'magic_shelf_counts' not in session:
255-
session['magic_shelf_counts'] = {}
256-
257-
counts = session['magic_shelf_counts']
258-
cache_updated = False
259-
now = time.time()
260-
CACHE_DURATION = 300 # 5 minutes
261-
262-
for shelf in g.magic_shelves_access:
263-
shelf_id_str = str(shelf.id)
264-
cached_data = counts.get(shelf_id_str)
270+
try:
271+
# Verify required tables exist before querying
272+
from sqlalchemy import inspect
273+
inspector = inspect(ub.session.bind)
274+
required_tables = ['magic_shelf', 'hidden_magic_shelf_templates']
275+
existing_tables = inspector.get_table_names()
276+
277+
missing_tables = [t for t in required_tables if t not in existing_tables]
278+
if missing_tables:
279+
log.error(f"Magic shelf tables missing from database: {missing_tables}. Run migration to create them.")
280+
g.magic_shelves_access = []
281+
return
282+
283+
# Get hidden items for this user (both system templates and custom shelves)
284+
hidden_items = ub.session.query(
285+
ub.HiddenMagicShelfTemplate.template_key,
286+
ub.HiddenMagicShelfTemplate.shelf_id
287+
).filter(
288+
ub.HiddenMagicShelfTemplate.user_id == current_user.id
289+
).all()
290+
291+
hidden_template_keys = {item.template_key for item in hidden_items if item.template_key}
292+
hidden_shelf_ids = {item.shelf_id for item in hidden_items if item.shelf_id}
293+
294+
# Get user's own shelves + public shelves (will filter hidden ones below)
295+
g.magic_shelves_access = ub.session.query(ub.MagicShelf).filter(
296+
or_(
297+
ub.MagicShelf.is_public == 1,
298+
ub.MagicShelf.user_id == current_user.id
299+
)
300+
).all()
301+
302+
log.debug(f"Found {len(g.magic_shelves_access)} total magic shelves for user {current_user.id} before filtering")
265303

266-
if cached_data and (now - cached_data.get('timestamp', 0) < CACHE_DURATION):
267-
shelf.book_count = cached_data['count']
268-
else:
269-
count = magic_shelf.get_book_count_for_magic_shelf(shelf.id)
270-
counts[shelf_id_str] = {'count': count, 'timestamp': now}
271-
shelf.book_count = count
272-
cache_updated = True
273-
274-
if cache_updated:
275-
session.modified = True
304+
# Filter out hidden items
305+
from . import magic_shelf
306+
filtered_shelves = []
307+
for shelf in g.magic_shelves_access:
308+
# Skip hidden system templates
309+
if shelf.is_system and shelf.user_id == current_user.id:
310+
# Find template key for this system shelf
311+
template_key = None
312+
for key, template in magic_shelf.SYSTEM_SHELF_TEMPLATES.items():
313+
if template['name'] == shelf.name:
314+
template_key = key
315+
break
316+
317+
# If template_key not found, this is an orphaned/deprecated system shelf
318+
if template_key is None:
319+
log.warning(f"System shelf '{shelf.name}' (ID: {shelf.id}) doesn't match any current template - may need migration")
320+
# Show it anyway - migration should clean it up on next restart
321+
filtered_shelves.append(shelf)
322+
continue
323+
324+
# Skip if hidden
325+
if template_key in hidden_template_keys:
326+
log.debug(f"Hiding system shelf template '{template_key}' for user {current_user.id}")
327+
continue
328+
329+
# Skip hidden custom public shelves (not owned by user)
330+
if shelf.is_public == 1 and shelf.user_id != current_user.id:
331+
if shelf.id in hidden_shelf_ids:
332+
log.debug(f"Hiding public shelf '{shelf.name}' (ID: {shelf.id}) for user {current_user.id}")
333+
continue
334+
335+
filtered_shelves.append(shelf)
336+
337+
g.magic_shelves_access = filtered_shelves
338+
log.debug(f"Filtered to {len(filtered_shelves)} visible magic shelves for user {current_user.id}")
339+
340+
# Magic Shelf Count Caching
341+
if 'magic_shelf_counts' not in session:
342+
session['magic_shelf_counts'] = {}
343+
344+
counts = session['magic_shelf_counts']
345+
cache_updated = False
346+
now = time.time()
347+
CACHE_DURATION = 300 # 5 minutes
348+
349+
for shelf in g.magic_shelves_access:
350+
shelf_id_str = str(shelf.id)
351+
cached_data = counts.get(shelf_id_str)
352+
353+
if cached_data and (now - cached_data.get('timestamp', 0) < CACHE_DURATION):
354+
shelf.book_count = cached_data['count']
355+
else:
356+
count = magic_shelf.get_book_count_for_magic_shelf(shelf.id)
357+
counts[shelf_id_str] = {'count': count, 'timestamp': now}
358+
shelf.book_count = count
359+
cache_updated = True
360+
361+
if cache_updated:
362+
session.modified = True
363+
except Exception as e:
364+
log.error(f"Error populating magic shelves for user {current_user.id}: {str(e)}", exc_info=True)
365+
g.magic_shelves_access = []
276366
else:
277367
g.magic_shelves_access = []
278368
try:
@@ -286,28 +376,6 @@ def shutdown_session(exception=None):
286376
if calibre_db.session_factory:
287377
calibre_db.session_factory.remove()
288378

289-
# Load user from reverse proxy header early in request lifecycle
290-
# This ensures current_user resolves correctly before any code accesses user settings
291-
@app.before_request
292-
def _load_reverse_proxy_user():
293-
"""
294-
Load user from reverse proxy authentication header if configured.
295-
Sets g.flask_httpauth_user early so that current_user proxy resolves correctly
296-
for user-specific settings like theme preferences.
297-
298-
This must run before any blueprint before_request handlers that access current_user.
299-
"""
300-
from flask import g, request
301-
302-
if config.config_allow_reverse_proxy_header_login:
303-
from . import usermanagement
304-
user = usermanagement.load_user_from_reverse_proxy_header(request)
305-
if user:
306-
g.flask_httpauth_user = user
307-
else:
308-
# Explicitly set to None to indicate we checked but found nothing
309-
g.flask_httpauth_user = None
310-
311379
from .schedule import register_scheduled_tasks, register_startup_tasks
312380
register_scheduled_tasks(config.schedule_reconnect)
313381
register_startup_tasks()

0 commit comments

Comments
 (0)