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 @@ -4,9 +4,14 @@ All notable changes to Library Manager will be documented in this file.

## [Unreleased]

## [0.9.0-beta.156] - 2026-07-15

### Changed
- **License restored to MIT** - Replaced AGPL-3.0 with the project's original MIT license and updated README and contribution terms to match.

### Documentation
- Synchronized the published version, provider lists, Skaldleita credential guidance, multilingual-provider notes, and configured request-rate defaults with current behavior.

## [0.9.0-beta.155] - 2026-07-15

### Added
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.153-blue.svg)](CHANGELOG.md)
[![Version](https://img.shields.io/badge/version-0.9.0--beta.156-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-MIT-orange.svg)](LICENSE)

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

## Recent Changes (stable)

> **beta.156** - **MIT License and Documentation Sync**
> - Restored the project's MIT license and aligned contribution terms.
> - Synchronized provider, Skaldleita credential, multilingual model, and request-rate guidance with current behavior.

> **beta.155** - **Local AI Is Provider-Agnostic**
> - Added llama.cpp and generic OpenAI-compatible API support with live `/v1/models` discovery.
> - Removed hardcoded Ollama model fallbacks and fixed `undefined` model entries across API response shapes.
Expand Down
2 changes: 1 addition & 1 deletion app.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
- Multi-provider AI (Gemini, OpenRouter, Ollama, OpenAI-compatible APIs)
"""

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

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

Check failure on line 744 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (E722)

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

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

Check failure on line 768 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (E722)

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

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

Check failure on line 1755 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (F541)

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

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

Check failure on line 1764 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (F541)

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

elif provider == 'ollama':
Expand All @@ -1771,7 +1771,7 @@
response_schema=response_schema,
)
if result:
logger.info(f"[PROVIDER CHAIN] Success with ollama")

Check failure on line 1774 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (F541)

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

elif provider == 'openai_compatible':
Expand Down Expand Up @@ -2237,11 +2237,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 2240 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (F541)

app.py:2240: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 2242 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (F541)

app.py:2242: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 2244 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (F541)

app.py:2244: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 @@ -2457,7 +2457,7 @@
if sample_path and os.path.exists(sample_path):
try:
os.unlink(sample_path)
except:

Check failure on line 2460 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (E722)

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

return result
Expand Down Expand Up @@ -2596,7 +2596,7 @@

# ============== DEEP SCANNER ==============

import re

Check failure on line 2599 in app.py

View workflow job for this annotation

GitHub Actions / lint

ruff (F811)

app.py:2599:8: F811 Redefinition of unused `re` from line 36: `re` redefined here app.py:36:8: previous definition of `re` here help: Remove definition: `re`
import hashlib

def detect_media_type(path):
Expand Down
2 changes: 1 addition & 1 deletion docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ When "Backup Tags" is enabled, original tags are saved to `.library-manager.tags
| OpenRouter | Varies by model |
| Ollama / local compatible API | Self-hosted |

The app defaults to 2000 calls/hour to stay well under limits.
Library Manager defaults to 200 requests/hour and allows a configured range of 10-500 requests/hour. Provider-specific backoff and circuit breakers apply when a service returns rate-limit responses.

## Config Files

Expand Down
5 changes: 1 addition & 4 deletions docs/FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,7 @@ Just renames folders. Files inside stay exactly where they are - only the folder

### What APIs does it use?

1. Audnexus (Audible data)
2. OpenLibrary (Internet Archive)
3. Google Books
4. Hardcover
Metadata can come from Skaldleita, Audnexus, OpenLibrary, Google Books, and Hardcover. Optional AI verification uses the configured Gemini, OpenRouter, Ollama, or OpenAI-compatible provider.

### Why Gemini over GPT-4?

Expand Down
3 changes: 2 additions & 1 deletion docs/FEATURE-language-preference.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ def get_localized_metadata(book_info, target_language):
- Gemini: Excellent multilingual (100+ languages)
- GPT-4/OpenRouter: Strong multilingual support
- Ollama (local): Depends on model, Llama 3 has decent multilingual
- llama.cpp/OpenAI-compatible: Depends on the model loaded by the user's server

### Audio Language Detection

Expand Down Expand Up @@ -200,7 +201,7 @@ Use cases:
- Audio detection uses existing Gemini integration (no new dependencies)
- Language codes follow ISO 639-1 standard
- Default behavior unchanged for existing users (`en`, preserve=true)
- **AI Translation Strategy**: All AI providers (Gemini, OpenRouter, Ollama) support multilingual prompts
- **AI Translation Strategy**: All configured AI paths (Gemini, OpenRouter, Ollama, and OpenAI-compatible servers) accept multilingual prompts; result quality depends on the selected model
- Add language instruction to existing prompts: "Respond in {language}"
- Titles returned should match user's preferred language when official translations exist
- AI handles translation automatically - no external translation API needed
2 changes: 1 addition & 1 deletion library_manager/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def _detect_data_dir():
"openrouter_api_key": "",
"gemini_api_key": "",
"openai_compatible_api_key": "",
"bookdb_api_key": "", # Optional API key for Skaldleita (not required for public endpoints)
"bookdb_api_key": "", # Optional personal key; the bundled shared key is used when empty
"abs_api_token": "",
"webhook_secret": "" # Shared secret for webhook authentication (referenced as {{webhook_secret}} in hook headers)
}
Expand Down
5 changes: 3 additions & 2 deletions library_manager/hints.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
HINTS = {
# === Identification Layers ===
'layer_1': 'Database Lookups: Searches Skaldleita, Audnexus, OpenLibrary, Google Books, and Hardcover for metadata matches. Free, fast, no API key needed.',
'layer_2': 'AI Verification: When databases return uncertain matches, AI (Gemini, OpenRouter, or Ollama) cross-checks the results. Uses your configured AI provider.',
'layer_2': 'AI Verification: When databases return uncertain matches, your configured provider (Gemini, OpenRouter, Ollama, or an OpenAI-compatible server) cross-checks the results.',
'layer_3': 'Audio Analysis: Extracts the first 90 seconds of audio to identify the book from narrator intros and title announcements. Can use Skaldleita GPU or your own Gemini API.',
'layer_4': 'Content Analysis: Last resort. Transcribes story text with Whisper and sends it to AI to identify the book. Slowest but catches edge cases other layers miss.',

Expand All @@ -15,6 +15,7 @@
'gemini': 'Google Gemini AI. Free tier offers 14,400 calls/day with Gemma 3 models. Handles both text verification and native audio analysis.',
'openrouter': 'API gateway to multiple AI models. Free models available (Llama, Gemma). Used as fallback when Gemini is unavailable or for Layer 4 content analysis.',
'ollama': 'Self-hosted AI. Run models locally with no API costs or rate limits. Requires separate Ollama installation.',
'openai_compatible': 'User-configured local or remote AI server with OpenAI-compatible model and chat-completions endpoints, including llama.cpp, LM Studio, vLLM, and LocalAI.',

# === Confidence & Verification ===
'confidence_threshold': 'Minimum confidence percentage before a book is considered identified. Higher values mean more certainty but slower processing. Lower values accept weaker matches faster.',
Expand Down Expand Up @@ -59,7 +60,7 @@
'openai_compatible_api_key': 'Optional bearer token for a user-configured OpenAI-compatible AI server.',
'openai_compatible_url': 'API base URL for llama.cpp, LM Studio, vLLM, LocalAI, or another OpenAI-compatible server.',
'openai_compatible_model': 'Model ID loaded from the configured server. Manual model IDs are also accepted.',
'bookdb_api_key': 'Optional Skaldleita API key. Increases your rate limit from 500 to 1000 requests per hour. Free to register.',
'bookdb_api_key': 'Optional personal Skaldleita API key. When empty, Library Manager uses its bundled shared credential for authenticated metadata and audio requests.',
'google_books_api_key': 'Optional Google Books API key for higher rate limits on book lookups.',
'ai_provider': 'Which AI to try first for text verification. Falls back to other configured providers automatically if the primary fails.',
'provider_chain': 'Order in which providers are tried. If the first one fails or is unavailable, the next one is used automatically.',
Expand Down
Loading