diff --git a/custom_components/bahmcloud_store/core.py b/custom_components/bahmcloud_store/core.py index 583d94d..061571b 100644 --- a/custom_components/bahmcloud_store/core.py +++ b/custom_components/bahmcloud_store/core.py @@ -1,9 +1,9 @@ from __future__ import annotations +import asyncio import logging from dataclasses import dataclass from typing import Any -from urllib.parse import urlparse from homeassistant.core import HomeAssistant from homeassistant.helpers.aiohttp_client import async_get_clientsession @@ -12,6 +12,7 @@ from homeassistant.util import yaml as ha_yaml from .storage import BCSStorage, CustomRepo from .views import StaticAssetsView, BCSApiView from .custom_repo_view import BCSCustomRepoView +from .providers import fetch_repo_info, detect_provider _LOGGER = logging.getLogger(__name__) @@ -36,7 +37,7 @@ class RepoItem: url: str source: str # "index" | "custom" - # Enrichment fields (filled later) + # Enrichment fields (best-effort) owner: str | None = None description: str | None = None provider: str | None = None @@ -70,28 +71,8 @@ class BCSCore: self.hass.http.register_view(BCSApiView(self)) self.hass.http.register_view(BCSCustomRepoView(self)) - @staticmethod - def _provider_name(repo_url: str) -> str: - """Best-effort provider detection by hostname.""" - host = urlparse(repo_url).netloc.lower() - if "github.com" in host: - return "github" - if "gitlab.com" in host: - return "gitlab" - # Likely self-hosted (Gitea/GitLab/other) - return "generic" - - @staticmethod - def _owner_from_url(repo_url: str) -> str | None: - """Extract owner/group from common URL patterns.""" - u = urlparse(repo_url.rstrip("/")) - parts = u.path.strip("/").split("/") - if len(parts) >= 2: - return parts[0] - return None - async def refresh(self) -> None: - """Refresh merged repo list (index + custom).""" + """Refresh merged repo list (index + custom) and enrich metadata.""" index_repos, refresh_seconds = await self._load_index_repos() self.refresh_seconds = refresh_seconds @@ -112,13 +93,33 @@ class BCSCore: source="custom", ) - # Enrich basic data (owner/provider); description will come later via provider APIs + # Basic provider detection (cheap) for r in merged.values(): - r.provider = self._provider_name(r.url) - r.owner = self._owner_from_url(r.url) + r.provider = detect_provider(r.url) + + # Enrich owner/description (best-effort; never break the store) + await self._enrich_repos(merged) self.repos = merged + async def _enrich_repos(self, merged: dict[str, RepoItem]) -> None: + """ + Enrich repositories using provider APIs (GitHub/Gitea). + This is intentionally best-effort and concurrency-limited. + """ + sem = asyncio.Semaphore(6) + + async def enrich_one(r: RepoItem) -> None: + async with sem: + info = await fetch_repo_info(self.hass, r.url) + r.provider = info.provider or r.provider + if info.owner: + r.owner = info.owner + if info.description: + r.description = info.description + + await asyncio.gather(*(enrich_one(r) for r in merged.values()), return_exceptions=True) + async def _load_index_repos(self) -> tuple[list[RepoItem], int]: """Load store.yaml and return (repos, refresh_seconds).""" session = async_get_clientsession(self.hass)