import contextlib
from concurrent.futures import ThreadPoolExecutor
from threading import Thread
from lib.api.tmdbv3api.tmdb import TMDb
from lib.clients.tmdb.utils.utils import tmdb_get
from lib.utils.kodi.utils import get_setting, kodilog
class StartupPreloader:
def run(self):
Thread(target=self._preload).start()
def _preload(self):
tmdb = TMDb()
tmdb.api_key = get_setting("tmdb_api_key", "b70756b7083d9ee60f849d82d94a0d80")
# Helper to fetch seasons for a list of shows
def _deep_preload_tv(results):
try:
if not results:
return
# Handle list vs dict (TMDB response structure variants)
items = []
if hasattr(results, "results"):
items = results.results
elif isinstance(results, dict):
items = results.get("results", [])
else:
with contextlib.suppress(BaseException):
items = list(results)
if not isinstance(items, list):
items = list(items)
top_items = items[:5]
for item in top_items:
try:
tmdb_id = (
getattr(item, "id", None) if hasattr(item, "id") else item.get("id")
)
(
getattr(item, "name", "Unknown")
if hasattr(item, "name")
else item.get("name", "Unknown")
)
if not tmdb_id:
continue
# 1. Fetch Show Details
details = tmdb_get("tv_details", tmdb_id)
if not details:
continue
# 2. Fetch Season 1
tmdb_get("season_details", {"id": tmdb_id, "season": 1})
# 3. Fetch Latest Season
num_seasons = (
getattr(details, "number_of_seasons", 0)
if hasattr(details, "number_of_seasons")
else details.get("number_of_seasons", 0)
)
if num_seasons > 1:
tmdb_get("season_details", {"id": tmdb_id, "season": num_seasons})
except Exception:
pass
except Exception as e:
import traceback
kodilog(f"[StartupPreloader] CRASH in _deep_preload_tv: {e}")
kodilog(traceback.format_exc())
with ThreadPoolExecutor(max_workers=5) as executor:
# 1. Fetch main lists in parallel
executor.submit(tmdb_get, "trending_movie", 1)
f_trend_tv = executor.submit(tmdb_get, "trending_tv", 1)
executor.submit(tmdb_get, "popular_movie", 1)
f_pop_tv = executor.submit(tmdb_get, "popular_shows", 1)
# Get results (this waits for the specific future, but others run in parallel)
# We treat TV lists specially to trigger deep preload
trending_tv = f_trend_tv.result()
popular_tv = f_pop_tv.result()
# Submit deep preload tasks
# This will run in the same pool, reusing workers as they free up
if trending_tv:
executor.submit(_deep_preload_tv, trending_tv)
if popular_tv:
executor.submit(_deep_preload_tv, popular_tv)