Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

All notable changes to Library Manager will be documented in this file.

## [0.9.0-beta.154] - 2026-07-14

### Fixed
- **#264: Auth headers on all Skaldleita API calls** — Added signed headers + API key to 4 call sites that previously sent keyless requests to the Skaldleita API: `api_book_detail`, `api_author_detail`, `api_series_detail`, and `identify_ebook_from_filename`. These endpoints now require authentication after the gate was changed to key-or-401.

## [0.9.0-beta.153] - 2026-06-12

### Security
Expand Down
28 changes: 21 additions & 7 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
- Multi-provider AI (Gemini, OpenRouter, Ollama)
"""

APP_VERSION = "0.9.0-beta.153"
APP_VERSION = "0.9.0-beta.154"
GITHUB_REPO = "deucebucket/library-manager" # Your GitHub repo

# Versioning Guide:
Expand Down Expand Up @@ -738,7 +738,7 @@
try:
with open(ERROR_REPORTS_PATH, 'r') as f:
reports = json.load(f)
except:

Check failure on line 741 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (E722)

app.py:741:13: E722 Do not use bare `except`
reports = []

# Add new report (keep last 100 reports to avoid file bloat)
Expand All @@ -762,7 +762,7 @@
try:
with open(ERROR_REPORTS_PATH, 'r') as f:
return json.load(f)
except:

Check failure on line 765 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (E722)

app.py:765:9: E722 Do not use bare `except`
return []
return []

Expand Down Expand Up @@ -1717,7 +1717,7 @@
continue
result = call_gemini(prompt, merged_config)
if result:
logger.info(f"[PROVIDER CHAIN] Success with gemini")

Check failure on line 1720 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (F541)

app.py:1720:33: F541 f-string without any placeholders help: Remove extraneous `f` prefix
return result

elif provider == 'openrouter':
Expand All @@ -1726,13 +1726,13 @@
continue
result = call_openrouter(prompt, merged_config)
if result:
logger.info(f"[PROVIDER CHAIN] Success with openrouter")

Check failure on line 1729 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (F541)

app.py:1729:33: F541 f-string without any placeholders help: Remove extraneous `f` prefix
return result

elif provider == 'ollama':
result = call_ollama(prompt, merged_config)
if result:
logger.info(f"[PROVIDER CHAIN] Success with ollama")

Check failure on line 1735 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (F541)

app.py:1735:33: F541 f-string without any placeholders help: Remove extraneous `f` prefix
return result

else:
Expand Down Expand Up @@ -1834,7 +1834,7 @@
return result
elif result and result.get('transcript'):
# Got transcript but no match - still useful, return for potential AI fallback
logger.info(f"[AUDIO CHAIN] BookDB returned transcript only")

Check failure on line 1837 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (F541)

app.py:1837:37: F541 f-string without any placeholders help: Remove extraneous `f` prefix
return result
elif result is None and attempt < max_retries - 1:
# Connection might be down, wait and retry
Expand Down Expand Up @@ -2166,11 +2166,11 @@
device = "cuda"
# int8 works on all CUDA devices including GTX 1080 (compute 6.1)
# float16 only works on newer GPUs (compute 7.0+)
logger.info(f"[WHISPER] Using CUDA GPU acceleration (10x faster)")

Check failure on line 2169 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (F541)

app.py:2169:29: F541 f-string without any placeholders help: Remove extraneous `f` prefix
else:
logger.info(f"[WHISPER] Using CPU (no CUDA GPU detected)")

Check failure on line 2171 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (F541)

app.py:2171:29: F541 f-string without any placeholders help: Remove extraneous `f` prefix
except ImportError:
logger.info(f"[WHISPER] Using CPU (ctranslate2 not available)")

Check failure on line 2173 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (F541)

app.py:2173:25: F541 f-string without any placeholders help: Remove extraneous `f` prefix

_whisper_model = WhisperModel(model_name, device=device, compute_type=compute_type)
_whisper_model_name = model_name
Expand Down Expand Up @@ -2295,9 +2295,14 @@
search_query = f"{author} {title}" if author else title
logger.debug(f"[EBOOK] Searching BookDB for: {search_query}")

api_key = config.get('bookdb_api_key') or BOOKDB_PUBLIC_KEY
headers = get_signed_headers() or {}
headers['X-API-Key'] = api_key

resp = requests.get(
f"{BOOKDB_API_URL}/search",
params={'q': search_query[:100]}, # Limit query length
headers=headers,
timeout=10
)

Expand Down Expand Up @@ -2381,7 +2386,7 @@
if sample_path and os.path.exists(sample_path):
try:
os.unlink(sample_path)
except:

Check failure on line 2389 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (E722)

app.py:2389:13: E722 Do not use bare `except`
pass

return result
Expand Down Expand Up @@ -11902,11 +11907,14 @@
"""
Get full book details from BookBucket + ABS status.
Used for hover cards and detail modals.
Uses public endpoint - no API key required.
"""
try:
# Fetch full book details from BookBucket
resp = requests.get(f"{BOOKDB_API_URL}/book/{book_id}", timeout=10)
secrets = load_secrets()
api_key = secrets.get('bookdb_api_key') or BOOKDB_PUBLIC_KEY
headers = get_signed_headers() or {}
headers['X-API-Key'] = api_key
resp = requests.get(f"{BOOKDB_API_URL}/book/{book_id}", headers=headers, timeout=10)

if resp.status_code != 200:
return jsonify({'error': f'Book not found (status {resp.status_code})'})
Expand Down Expand Up @@ -11977,10 +11985,13 @@
"""
Get author details from BookBucket.
Used for hover cards on author search results.
Uses public endpoint - no API key required.
"""
try:
resp = requests.get(f"{BOOKDB_API_URL}/author/{author_id}", timeout=10)
secrets = load_secrets()
api_key = secrets.get('bookdb_api_key') or BOOKDB_PUBLIC_KEY
headers = get_signed_headers() or {}
headers['X-API-Key'] = api_key
resp = requests.get(f"{BOOKDB_API_URL}/author/{author_id}", headers=headers, timeout=10)

if resp.status_code != 200:
return jsonify({'error': f'Author not found (status {resp.status_code})'})
Expand All @@ -12000,10 +12011,13 @@
"""
Get series details from BookBucket.
Used for hover cards on series search results.
Uses public endpoint - no API key required.
"""
try:
resp = requests.get(f"{BOOKDB_API_URL}/series/{series_id}", timeout=10)
secrets = load_secrets()
api_key = secrets.get('bookdb_api_key') or BOOKDB_PUBLIC_KEY
headers = get_signed_headers() or {}
headers['X-API-Key'] = api_key
resp = requests.get(f"{BOOKDB_API_URL}/series/{series_id}", headers=headers, timeout=10)

if resp.status_code != 200:
return jsonify({'error': f'Series not found (status {resp.status_code})'})
Expand Down
Loading