Skip to content

direct_download_repository

appimage_updater.repositories.direct_download_repository

Direct download repository implementation for applications with static download URLs.

This handles applications that provide direct download links without a traditional release API, such as "latest" symlinks or version-embedded URLs.

DirectDownloadRepository(timeout=30, user_agent=None, **kwargs)

Repository client for direct download URLs with static patterns.

Source code in src/appimage_updater/repositories/direct_download_repository.py
def __init__(self, timeout: int = 30, user_agent: str | None = None, **kwargs: Any):
    super().__init__(timeout, user_agent, **kwargs)

repository_type property

Get the repository type identifier.

detect_repository_type(url)

Detect if URL is a direct download pattern.

Source code in src/appimage_updater/repositories/direct_download_repository.py
def detect_repository_type(self, url: str) -> bool:
    """Detect if URL is a direct download pattern."""
    # Patterns that indicate direct downloads
    direct_patterns = [
        r".*-latest.*\.AppImage$",  # YubiKey Manager pattern
        r".*\.AppImage$",  # Direct AppImage links
        r".*/download/?$",  # Generic download pages
        r".*openrgb\.org/releases.*",  # OpenRGB releases page
        r".*/releases\.html?$",  # Generic releases pages
        r".*/releases/?$",  # Generic releases directories
    ]

    return any(re.match(pattern, url, re.IGNORECASE) for pattern in direct_patterns)

generate_pattern_from_releases(url) async

Generate file pattern from releases.

Source code in src/appimage_updater/repositories/direct_download_repository.py
async def generate_pattern_from_releases(self, url: str) -> str | None:
    """Generate file pattern from releases."""
    try:
        releases = await self.get_releases(url, limit=5)
        if not releases:
            return None

        # Extract AppImage asset names
        asset_names = self._extract_appimage_names_from_releases(releases)
        if not asset_names:
            return None

        # Generate pattern based on first asset name
        base_name = self._clean_base_name(asset_names[0])
        return self._create_flexible_pattern(base_name)

    except Exception as e:
        logger.error(f"Failed to generate pattern for {url}: {e}")
        return None

get_latest_release(url) async

Get the latest release for direct download URL.

Source code in src/appimage_updater/repositories/direct_download_repository.py
async def get_latest_release(self, url: str) -> Release:
    """Get the latest release for direct download URL."""
    releases = await self.get_releases(url, limit=1)
    if not releases:
        raise RepositoryError(f"No releases found for {url}")
    return releases[0]

get_latest_release_including_prerelease(repo_url) async

Get the latest release including prereleases (same as latest for direct downloads).

Source code in src/appimage_updater/repositories/direct_download_repository.py
async def get_latest_release_including_prerelease(self, repo_url: str) -> Release:
    """Get the latest release including prereleases (same as latest for direct downloads)."""
    return await self.get_latest_release(repo_url)

get_releases(url, limit=10) async

Get releases for direct download URL.

Source code in src/appimage_updater/repositories/direct_download_repository.py
async def get_releases(self, url: str, limit: int = 10) -> list[Release]:
    """Get releases for direct download URL."""
    try:
        # Use progressive timeout strategy for better performance
        progressive_client = create_progressive_client(self.timeout)

        # Check if this is a releases page that needs parsing
        # Exclude direct AppImage URLs from releases page handling
        if any(
            pattern in url.lower() for pattern in ["releases.html", "releases/", "openrgb.org/releases"]
        ) and not url.endswith(".AppImage"):
            return await self._handle_releases_page_progressive(progressive_client, url)
        else:
            # Handle direct download URLs
            return await self._handle_direct_download_progressive(progressive_client, url)

    except Exception as e:
        logger.error(f"Failed to get releases for {url}: {e}")
        raise RepositoryError(f"Failed to fetch release information: {e}") from e

normalize_repo_url(url)

Normalize direct download URL.

Source code in src/appimage_updater/repositories/direct_download_repository.py
def normalize_repo_url(self, url: str) -> tuple[str, bool]:
    """Normalize direct download URL."""
    # For direct downloads, we typically don't modify the URL
    return url, False

parse_repo_url(url)

Parse direct download URL to extract meaningful components.

Source code in src/appimage_updater/repositories/direct_download_repository.py
def parse_repo_url(self, url: str) -> tuple[str, str]:
    """Parse direct download URL to extract meaningful components."""
    # For direct downloads, we'll use domain and path as identifiers
    try:
        parsed = urlparse(url)
        domain = parsed.netloc.replace("www.", "")
        path_parts = [p for p in parsed.path.split("/") if p]
        repo_name = path_parts[-1] if path_parts else "download"
        return domain, repo_name
    except Exception as e:
        raise RepositoryError(f"Invalid URL format: {url}") from e

should_enable_prerelease(url) async

Check if prerelease should be enabled (always False for direct downloads).

Source code in src/appimage_updater/repositories/direct_download_repository.py
async def should_enable_prerelease(self, url: str) -> bool:
    """Check if prerelease should be enabled (always False for direct downloads)."""
    return False