update to TVDB

This commit is contained in:
2025-09-17 15:32:34 -04:00
parent 532ea02a5b
commit 539b09fc5b
2 changed files with 59 additions and 12 deletions
+1 -1
View File
@@ -1 +1 @@
1.6.3 1.6.5
+57 -10
View File
@@ -20,11 +20,15 @@ def _get_json(url: str, timeout: int = 20, headers: Dict[str, str] = None, suppr
req = UrlRequest(url, headers=headers or {"Accept": "application/json"}) req = UrlRequest(url, headers=headers or {"Accept": "application/json"})
with urlopen(req, timeout=timeout) as resp: with urlopen(req, timeout=timeout) as resp:
return json.loads(resp.read().decode("utf-8")) return json.loads(resp.read().decode("utf-8"))
except Exception as e: except HTTPError as e:
# Handle HTTP 400/404 errors more gracefully for APIs where missing data is normal # Handle specific HTTP errors more gracefully
if suppress_404 and ("400" in str(e) or "404" in str(e)): if suppress_404 and e.code in [400, 404]:
_log("DEBUG", f"GET {url} - item not found (expected): {e}") _log("DEBUG", f"TVDB API: {url} - item not found (HTTP {e.code}) - this is expected")
return None
else: else:
_log("WARNING", f"GET {url} failed: HTTP Error {e.code}: {e.reason}")
return None
except Exception as e:
_log("WARNING", f"GET {url} failed: {e}") _log("WARNING", f"GET {url} failed: {e}")
return None return None
@@ -55,12 +59,14 @@ class TVDBClient:
def _get_token(self) -> Optional[str]: def _get_token(self) -> Optional[str]:
"""Get TVDB auth token (cached)""" """Get TVDB auth token (cached)"""
if not self.api_key: if not self.api_key:
_log("DEBUG", "TVDB: No API key provided")
return None return None
if time.time() < self._token_expires and self._token: if time.time() < self._token_expires and self._token:
return self._token return self._token
try: try:
_log("DEBUG", f"TVDB: Authenticating with API key: {self.api_key[:8]}...")
req = UrlRequest( req = UrlRequest(
f"{self.base_url}/login", f"{self.base_url}/login",
data=json.dumps({"apikey": self.api_key}).encode('utf-8'), data=json.dumps({"apikey": self.api_key}).encode('utf-8'),
@@ -68,35 +74,71 @@ class TVDBClient:
) )
with urlopen(req, timeout=10) as resp: with urlopen(req, timeout=10) as resp:
data = json.loads(resp.read().decode("utf-8")) data = json.loads(resp.read().decode("utf-8"))
_log("DEBUG", f"TVDB login response: {data}")
if data.get("status") == "success": if data.get("status") == "success":
self._token = data["data"]["token"] self._token = data["data"]["token"]
self._token_expires = time.time() + 3600 # 1 hour self._token_expires = time.time() + 3600 # 1 hour
_log("INFO", f"✅ TVDB: Authentication successful")
return self._token return self._token
else:
_log("WARNING", f"TVDB login failed: {data}")
except Exception as e: except Exception as e:
_log("WARNING", f"TVDB login failed: {e}") _log("WARNING", f"TVDB login failed: {e}")
return None return None
def imdb_to_tvdb_series_id(self, imdb_id: str) -> Optional[str]: def imdb_to_tvdb_series_id(self, imdb_id: str) -> Optional[str]:
"""Convert IMDB ID to TVDB series ID""" """Convert IMDB ID to TVDB series ID using TVDB v4 API"""
token = self._get_token() token = self._get_token()
if not token: if not token:
return None return None
try: try:
# Search by remote ID (IMDB) # Try the official v4 search endpoint first
url = f"{self.base_url}/search/remoteid?remoteId={imdb_id}&type=series" # According to docs: /search?query=imdb_id&type=series
url = f"{self.base_url}/search?query={imdb_id}&type=series&meta=translations"
headers = {"Authorization": f"Bearer {token}"} headers = {"Authorization": f"Bearer {token}"}
_log("DEBUG", f"TVDB: Searching for {imdb_id} using /search endpoint")
data = _get_json(url, headers=headers, suppress_404=True) data = _get_json(url, headers=headers, suppress_404=True)
if data and data.get("status") == "success" and data.get("data"):
series_list = data["data"]
_log("DEBUG", f"TVDB search response: found {len(series_list)} results")
# Look for exact IMDB match in results
for series in series_list:
# Check if this series has the IMDB ID we're looking for
remote_ids = series.get("remote_ids", [])
for remote in remote_ids:
if (remote.get("source_name") == "IMDB" and
remote.get("remote_id") == imdb_id):
tvdb_id = series.get("tvdb_id") or series.get("id")
if tvdb_id:
_log("INFO", f"✅ TVDB: Found series {imdb_id}{tvdb_id}")
return str(tvdb_id)
# If no exact match, try the first result if it looks promising
if series_list:
first_result = series_list[0]
tvdb_id = first_result.get("tvdb_id") or first_result.get("id")
if tvdb_id:
_log("INFO", f"✅ TVDB: Found series {imdb_id}{tvdb_id} (first result)")
return str(tvdb_id)
# If search didn't work, try the legacy remoteid endpoint
_log("DEBUG", f"TVDB: Trying legacy remoteid endpoint for {imdb_id}")
url = f"{self.base_url}/search/remoteid?remoteId={imdb_id}&type=series"
data = _get_json(url, headers=headers, suppress_404=True)
if data and data.get("status") == "success" and data.get("data"): if data and data.get("status") == "success" and data.get("data"):
series_list = data["data"] series_list = data["data"]
if series_list and len(series_list) > 0: if series_list and len(series_list) > 0:
tvdb_id = series_list[0].get("id") tvdb_id = series_list[0].get("id")
if tvdb_id: if tvdb_id:
_log("INFO", f"✅ TVDB: Found series {imdb_id}{tvdb_id}") _log("INFO", f"✅ TVDB: Found series {imdb_id}{tvdb_id} (legacy endpoint)")
return str(tvdb_id) return str(tvdb_id)
# If we get here, the series wasn't found in TVDB (common for newer shows) # If we get here, the series wasn't found in TVDB
_log("DEBUG", f"TVDB: No series found for IMDb {imdb_id} (not available in TVDB)") _log("DEBUG", f"TVDB: No series found for IMDb {imdb_id} (not available in TVDB)")
except Exception as e: except Exception as e:
@@ -528,8 +570,13 @@ class ExternalClientManager:
def get_tvdb_series_id(self, imdb_id: str) -> Optional[str]: def get_tvdb_series_id(self, imdb_id: str) -> Optional[str]:
"""Get TVDB series ID from IMDB ID""" """Get TVDB series ID from IMDB ID"""
# Check if TVDB lookups are disabled
if os.environ.get("DISABLE_TVDB", "false").lower() in ["true", "1", "yes"]:
_log("DEBUG", "TVDB lookups disabled via DISABLE_TVDB environment variable")
return None
if not self.tvdb.api_key: if not self.tvdb.api_key:
_log("WARNING", "TVDB API key not configured, skipping TVDB ID lookup") _log("INFO", "TVDB API key not configured, skipping TVDB ID lookup (set TVDB_API_KEY to enable)")
return None return None
return self.tvdb.imdb_to_tvdb_series_id(imdb_id) return self.tvdb.imdb_to_tvdb_series_id(imdb_id)