diff --git a/custom_components/bahmcloud_store/providers.py b/custom_components/bahmcloud_store/providers.py index 4580e11..68ab5d4 100644 --- a/custom_components/bahmcloud_store/providers.py +++ b/custom_components/bahmcloud_store/providers.py @@ -9,6 +9,8 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession _LOGGER = logging.getLogger(__name__) +UA = "BahmcloudStore/0.4.0 (Home Assistant)" + @dataclass class RepoInfo: @@ -18,17 +20,27 @@ class RepoInfo: provider: str | None = None default_branch: str | None = None - # Latest version best-effort latest_version: str | None = None latest_version_source: str | None = None # "release" | "tag" | None +def _normalize_repo_name(name: str | None) -> str | None: + if not name: + return None + n = name.strip() + if n.endswith(".git"): + n = n[:-4] + return n or None + + def _split_owner_repo(repo_url: str) -> tuple[str | None, str | None]: u = urlparse(repo_url.rstrip("/")) parts = [p for p in u.path.strip("/").split("/") if p] if len(parts) < 2: return None, None - return parts[0], parts[1] + owner = parts[0].strip() or None + repo = _normalize_repo_name(parts[1]) + return owner, repo def detect_provider(repo_url: str) -> str: @@ -55,26 +67,18 @@ async def _safe_json(session, url: str, *, headers: dict | None = None, timeout: async def _github_latest_version(hass: HomeAssistant, owner: str, repo: str) -> tuple[str | None, str | None]: session = async_get_clientsession(hass) + headers = { + "Accept": "application/vnd.github+json", + "User-Agent": UA, + } - # 1) Latest release - data, status = await _safe_json( - session, - f"https://api.github.com/repos/{owner}/{repo}/releases/latest", - headers={"Accept": "application/vnd.github+json"}, - timeout=15, - ) + data, _ = await _safe_json(session, f"https://api.github.com/repos/{owner}/{repo}/releases/latest", headers=headers) if isinstance(data, dict): tag = data.get("tag_name") or data.get("name") if isinstance(tag, str) and tag.strip(): return tag.strip(), "release" - # 2) Latest tag (first item) - data, status = await _safe_json( - session, - f"https://api.github.com/repos/{owner}/{repo}/tags?per_page=1", - headers={"Accept": "application/vnd.github+json"}, - timeout=15, - ) + data, _ = await _safe_json(session, f"https://api.github.com/repos/{owner}/{repo}/tags?per_page=1", headers=headers) if isinstance(data, list) and data: tag = data[0].get("name") if isinstance(tag, str) and tag.strip(): @@ -86,23 +90,13 @@ async def _github_latest_version(hass: HomeAssistant, owner: str, repo: str) -> async def _gitea_latest_version(hass: HomeAssistant, base: str, owner: str, repo: str) -> tuple[str | None, str | None]: session = async_get_clientsession(hass) - # 1) Releases (first item) - data, status = await _safe_json( - session, - f"{base}/api/v1/repos/{owner}/{repo}/releases?limit=1", - timeout=15, - ) + data, _ = await _safe_json(session, f"{base}/api/v1/repos/{owner}/{repo}/releases?limit=1") if isinstance(data, list) and data: tag = data[0].get("tag_name") or data[0].get("name") if isinstance(tag, str) and tag.strip(): return tag.strip(), "release" - # 2) Tags (first item) - data, status = await _safe_json( - session, - f"{base}/api/v1/repos/{owner}/{repo}/tags?limit=1", - timeout=15, - ) + data, _ = await _safe_json(session, f"{base}/api/v1/repos/{owner}/{repo}/tags?limit=1") if isinstance(data, list) and data: tag = data[0].get("name") if isinstance(tag, str) and tag.strip(): @@ -132,16 +126,14 @@ async def fetch_repo_info(hass: HomeAssistant, repo_url: str) -> RepoInfo: try: if provider == "github": - api = f"https://api.github.com/repos/{owner}/{repo}" - data, status = await _safe_json( - session, - api, - headers={"Accept": "application/vnd.github+json"}, - timeout=15, - ) + headers = { + "Accept": "application/vnd.github+json", + "User-Agent": UA, + } + data, _ = await _safe_json(session, f"https://api.github.com/repos/{owner}/{repo}", headers=headers) if isinstance(data, dict): info.description = data.get("description") - info.repo_name = data.get("name") or repo + info.repo_name = _normalize_repo_name(data.get("name")) or repo info.default_branch = data.get("default_branch") or "main" if isinstance(data.get("owner"), dict) and data["owner"].get("login"): info.owner = data["owner"]["login"] @@ -155,11 +147,10 @@ async def fetch_repo_info(hass: HomeAssistant, repo_url: str) -> RepoInfo: u = urlparse(repo_url.rstrip("/")) base = f"{u.scheme}://{u.netloc}" - api = f"{base}/api/v1/repos/{owner}/{repo}" - data, status = await _safe_json(session, api, timeout=15) + data, _ = await _safe_json(session, f"{base}/api/v1/repos/{owner}/{repo}") if isinstance(data, dict): info.description = data.get("description") - info.repo_name = data.get("name") or repo + info.repo_name = _normalize_repo_name(data.get("name")) or repo info.default_branch = data.get("default_branch") or "main" if isinstance(data.get("owner"), dict) and data["owner"].get("login"): info.owner = data["owner"]["login"]