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
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@

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

## [0.9.0-beta.149] - 2026-04-17

### Fixed

- **Issue #211: Watch-folder failure tracking silently dropped** — Three
`INSERT` statements in `process_watch_folder` (`app.py:6906`, `6914`,
`6944`) referenced `added_at` on the `books` table, but the schema column
is `created_at`. Every insert raised `sqlite3.OperationalError: table
books has no column named added_at`. Two `except` blocks caught it with
`logger.debug`, hiding the error at default log levels. Effects:
- Successful watch-folder moves never produced a `pending` or
`needs_attention` row in the books table.
- Failed watch-folder moves never produced a `watch_folder_error` row —
users had no UI surface for the failure, only a log line.
- Fix: renamed `added_at` to `created_at` in all three INSERTs;
raised both swallow-except blocks from `logger.debug` to
`logger.warning(..., exc_info=True)` so the same class of silent
failure can't rot unnoticed again.
- Surfaced during live testing of #209. Bug has existed since the
watch-folder feature was introduced.

---

## [0.9.0-beta.148] - 2026-04-17

### Fixed
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

**Smart Audiobook Library Organizer with Multi-Source Metadata & AI Verification**

[![Version](https://img.shields.io/badge/version-0.9.0--beta.148-blue.svg)](CHANGELOG.md)
[![Version](https://img.shields.io/badge/version-0.9.0--beta.149-blue.svg)](CHANGELOG.md)
[![Docker](https://img.shields.io/badge/docker-ghcr.io-blue.svg)](https://ghcr.io/deucebucket/library-manager)
[![License](https://img.shields.io/badge/license-AGPL--3.0-blue.svg)](LICENSE)

Expand All @@ -16,6 +16,10 @@

## Recent Changes (stable)

> **beta.149** - **Fix: Watch-Folder Move Failures Now Appear in the UI** (Issue #211)
> - Three `INSERT` statements in the watch-folder worker referenced a phantom `added_at` column on the `books` table (the real column is `created_at`). Every insert silently raised `OperationalError`, caught by a `logger.debug` that hid the error. Result: watch-folder move failures never produced a `watch_folder_error` row — the UI never showed the failure, users only saw it in logs.
> - Fixed the column name and raised the swallow-except log level to `warning` with full traceback so future DB errors don't rot silently.

> **beta.148** - **Fix: Watch-Folder Retry Loop Across Restarts + Skaldleita server_notice** (Issue #208)
> - **Persistent watch-folder dedup** - `watch_folder_processed` is now a SQLite table instead of an in-memory `set()`. Restarts no longer wipe it, killing the retry loop that had one LM instance hammering Skaldleita's `/match` every 30 seconds on the same file for days.
> - **Honors Skaldleita's abort signal** - When the server detects a retry loop it sends a `server_notice` in the response. LM now logs it (with an upgrade URL) and, on `action=abort_task`, stops retrying that file immediately.
Expand Down
15 changes: 9 additions & 6 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.148"
APP_VERSION = "0.9.0-beta.149"
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 @@ -2377,7 +2377,7 @@
if sample_path and os.path.exists(sample_path):
try:
os.unlink(sample_path)
except:

Check failure on line 2380 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (E722)

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

return result
Expand Down Expand Up @@ -6903,15 +6903,15 @@
# Unknown author - requires user intervention before processing
# Issue #57: Include source_type for watch folder tracking
c.execute('''INSERT OR REPLACE INTO books
(path, current_author, current_title, status, error_message, source_type, added_at, updated_at)
(path, current_author, current_title, status, error_message, source_type, created_at, updated_at)
VALUES (?, ?, ?, 'needs_attention', ?, 'watch_folder', datetime('now'), datetime('now'))''',
(new_path, author, title, 'Watch folder: Could not determine author - please review and correct'))
logger.info(f"Watch folder: Flagged for attention (unknown author): {title}")
else:
# Known author - normal processing
# Issue #57: Include source_type for watch folder tracking
c.execute('''INSERT OR REPLACE INTO books
(path, current_author, current_title, status, source_type, added_at, updated_at)
(path, current_author, current_title, status, source_type, created_at, updated_at)
VALUES (?, ?, ?, 'pending', 'watch_folder', datetime('now'), datetime('now'))''',
(new_path, author, title))
# Issue #126: Auto-enqueue for full pipeline processing
Expand All @@ -6923,7 +6923,8 @@
logger.info(f"Watch folder: Auto-enqueued for processing: {author}/{title}")
conn.commit()
except Exception as e:
logger.debug(f"Watch folder: Could not add to books table: {e}")
# Issue #211: was logger.debug which hid the real exception.
logger.warning(f"Watch folder: Could not add to books table: {e}", exc_info=True)
else:
logger.error(f"Watch folder: Failed to move {item.name}: {error}")
# Issue #49: Track failed items in the database so user can see and fix them
Expand All @@ -6941,13 +6942,15 @@
else:
# Insert new record for the failed item
c.execute('''INSERT INTO books
(path, current_author, current_title, status, error_message, source_type, added_at, updated_at)
(path, current_author, current_title, status, error_message, source_type, created_at, updated_at)
VALUES (?, ?, ?, 'watch_folder_error', ?, 'watch_folder', datetime('now'), datetime('now'))''',
(item_path, author, title, f'Watch folder: {error}'))
conn.commit()
logger.info(f"Watch folder: Tracked failure for user review: {item.name}")
except Exception as db_err:
logger.debug(f"Watch folder: Could not track failure in DB: {db_err}")
# Issue #211: was logger.debug which hid the real exception; raise level
# so failures surface in normal operation instead of rotting silently.
logger.warning(f"Watch folder: Could not track failure in DB: {db_err}", exc_info=True)

except Exception as e:
logger.error(f"Watch folder: Error processing {item_path}: {e}")
Expand Down
Loading