Add connectivity check to diagnose why all metadata APIs return 0 hits

All four sources returning 0 results is a strong signal of a network
problem (DNS, firewall, proxy, Docker isolation) rather than four
independent matching bugs.

New endpoint GET /api/items/match/connectivity:
- Pings Google, MusicBrainz, OpenLibrary, GoogleBooks, DNB
- Returns per-target HTTP status, byte count, latency, error
- Surfaces any HTTP_PROXY / HTTPS_PROXY env vars that httpx would use

UI: New "Connectivity-Check" button in BookDetail. Result panel shows
each target green (HTTP 200) or red (error/timeout), so the user can
immediately see whether the backend has outbound internet access at
all, or whether it's a per-API issue.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Audiolib
2026-05-26 19:30:07 +02:00
parent e3e6492b1f
commit 4fccb7abae
3 changed files with 103 additions and 1 deletions

View File

@@ -52,6 +52,60 @@ async def search_match(
return {"results": results}
@router.get("/match/connectivity")
async def check_connectivity(
current_user: User = Depends(get_current_user),
):
"""Testet ob das Backend die externen Metadaten-APIs erreichen kann."""
import httpx
import time
targets = [
("Google", "https://www.google.com"),
("MusicBrainz", "https://musicbrainz.org/ws/2/release?query=test&fmt=json&limit=1"),
("OpenLibrary", "https://openlibrary.org/search.json?title=test&limit=1"),
("GoogleBooks", "https://www.googleapis.com/books/v1/volumes?q=test&maxResults=1"),
("DNB", "https://services.dnb.de/sru/dnb?version=1.1&operation=searchRetrieve&query=tit%3Dtest&maximumRecords=1"),
]
headers = {"User-Agent": "audiolib/1.0"}
results = []
async with httpx.AsyncClient(headers=headers, timeout=15, follow_redirects=True) as client:
for name, url in targets:
t0 = time.time()
try:
r = await client.get(url)
results.append({
"name": name,
"url": url,
"ok": True,
"status": r.status_code,
"bytes": len(r.content),
"ms": int((time.time() - t0) * 1000),
"body_snippet": (r.text[:150] if r.status_code != 200 else None),
})
except Exception as e:
results.append({
"name": name,
"url": url,
"ok": False,
"error": f"{type(e).__name__}: {e}",
"ms": int((time.time() - t0) * 1000),
})
# Auch Env-Variablen die httpx beeinflussen
import os
proxy_env = {
k: v for k, v in os.environ.items()
if k.upper() in ("HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY", "ALL_PROXY")
}
return {
"results": results,
"proxy_env": proxy_env or "keine",
}
@router.get("/match/debug")
async def debug_match(
title: str,