Documentation
¶
Overview ¶
Package source provides metadata fetching from various sources.
Package source handles fetching APKs from various sources.
Index ¶
- Constants
- Variables
- func DefaultMetadataSources(cfg *config.Config) []string
- func DeleteCachedDownload(downloadURL, filename string) error
- func DetectPlayStore(url string) bool
- func DownloadCacheDir() string
- func DownloadCacheKey(downloadURL string) string
- func DownloadHTTP(ctx context.Context, client *http.Client, url, destPath string, ...) error
- func FetchReleaseNotes(ctx context.Context, pathOrURL string, version string, baseDir string) (string, error)
- func GetCachedDownload(downloadURL, filename string) string
- func GetPlayStorePackageID(url string) string
- func HasUnsupportedArchitecture(filename string) bool
- func HasValidAPKs(assets []*Asset) bool
- func IsAPKAsset(name, url string) bool
- func IsAPKURL(rawURL string) bool
- func SaveToDownloadCache(downloadURL, filename, srcPath string) (string, error)
- type AppMetadata
- type Asset
- type CacheClearer
- type CacheCommitter
- type CacheSkipper
- type CachedReleaseProvider
- type DownloadProgress
- type FDroid
- func (f *FDroid) CommitCache() error
- func (f *FDroid) Download(ctx context.Context, asset *Asset, destDir string, progress DownloadProgress) (string, error)
- func (f *FDroid) FetchLatestRelease(ctx context.Context) (*Release, error)
- func (f *FDroid) FetchMetadata(ctx context.Context) (*fdroidMetadata, error)
- func (f *FDroid) GetCachedRelease() *Release
- func (f *FDroid) PackageID() string
- func (f *FDroid) RepoInfo() *config.FDroidRepoInfo
- func (f *FDroid) SetSkipCache(v bool)
- func (f *FDroid) Type() config.SourceType
- type GitHub
- func (g *GitHub) ClearCache() error
- func (g *GitHub) CommitCache() error
- func (g *GitHub) Download(ctx context.Context, asset *Asset, destDir string, progress DownloadProgress) (string, error)
- func (g *GitHub) FetchLatestRelease(ctx context.Context) (*Release, error)
- func (g *GitHub) GetCachedRelease() *Release
- func (g *GitHub) SetSkipCache(v bool)
- func (g *GitHub) Type() config.SourceType
- type GitLab
- type Gitea
- type Local
- type MetadataError
- type MetadataFetcher
- type MetadataResult
- type Options
- type ParsedRelease
- type PlayStore
- type PlayStoreMetadata
- type ProgressReader
- type Release
- type Source
- type StallTimeoutReader
- type Web
- func (w *Web) ClearCache() error
- func (w *Web) CommitCache() error
- func (w *Web) Download(ctx context.Context, asset *Asset, destDir string, progress DownloadProgress) (string, error)
- func (w *Web) FetchLatestRelease(ctx context.Context) (*Release, error)
- func (w *Web) GetCachedRelease() *Release
- func (w *Web) SetSkipCache(v bool)
- func (w *Web) Type() config.SourceType
Constants ¶
const MaxDownloadSize int64 = 600 * 1024 * 1024 // 600MB
MaxDownloadSize is the hard cap for APK downloads (and any HTTP downloads via DownloadHTTP) to avoid excessive bandwidth or disk usage.
const MaxRemoteDownloadSize = 20 * 1024 * 1024 // 20MB
MaxRemoteDownloadSize is the maximum size for remote downloads (images, metadata, etc.) This prevents memory exhaustion from malicious or unexpectedly large responses.
Variables ¶
var ErrNotModified = fmt.Errorf("release not modified")
ErrNotModified is returned when the release hasn't changed since the last check.
Functions ¶
func DefaultMetadataSources ¶
DefaultMetadataSources returns the metadata sources to use. The base source type (github, gitlab, fdroid) is always included automatically. Any additional sources from metadata_sources config are appended. Returns nil if no metadata source applies.
func DeleteCachedDownload ¶
DeleteCachedDownload removes a cached download file. Returns nil if the file doesn't exist or was successfully deleted.
func DetectPlayStore ¶
DetectPlayStore checks if a URL is a Play Store URL.
func DownloadCacheDir ¶
func DownloadCacheDir() string
DownloadCacheDir returns the directory for caching downloaded APKs.
func DownloadCacheKey ¶
DownloadCacheKey generates a cache key for a download URL. The key is a hex-encoded SHA256 hash prefix of the URL.
func DownloadHTTP ¶
func DownloadHTTP(ctx context.Context, client *http.Client, url, destPath string, expectedSize int64, progress DownloadProgress) error
DownloadHTTP downloads a file from a URL with optional progress reporting. This is a shared helper for all HTTP-based sources. Uses stall-based timeout: fails only if no data received for 30s, not after a fixed total time.
func FetchReleaseNotes ¶
func FetchReleaseNotes(ctx context.Context, pathOrURL string, version string, baseDir string) (string, error)
FetchReleaseNotes fetches release notes from a URL or local file. If the content follows the Keep a Changelog format and a version is provided, only the section for that version is extracted.
func GetCachedDownload ¶
GetCachedDownload checks if a download is already cached. Returns the path if cached and valid, empty string otherwise.
func GetPlayStorePackageID ¶
GetPlayStorePackageID extracts the package ID from a Play Store URL.
func HasUnsupportedArchitecture ¶
HasUnsupportedArchitecture returns true if the filename explicitly indicates an unsupported architecture (x86, x86_64, etc.).
func HasValidAPKs ¶ added in v0.3.1
HasValidAPKs returns true if the assets contain at least one APK file. Used to determine if a release is a valid mobile release (vs desktop-only).
func IsAPKAsset ¶ added in v0.3.1
IsAPKAsset checks if an asset (by name or URL) is an APK file.
func IsAPKURL ¶ added in v0.3.1
IsAPKURL checks if a URL points to an APK file. Properly handles URLs with query parameters.
func SaveToDownloadCache ¶
SaveToDownloadCache saves a downloaded file to the cache. Returns the cached path on success.
Types ¶
type AppMetadata ¶
type AppMetadata struct {
Name string
Description string
Summary string
Website string
License string
Tags []string
ImageURLs []string
IconURL string // URL to app icon (from Play Store or F-Droid)
}
AppMetadata contains enriched app metadata from external sources.
func FetchPlayStoreMetadata ¶
func FetchPlayStoreMetadata(ctx context.Context, packageID string) (*AppMetadata, error)
FetchPlayStoreMetadata is a convenience function to fetch metadata by package ID.
type Asset ¶
type Asset struct {
Name string // Filename
URL string // Download URL (empty for local files)
Size int64 // Size in bytes (0 if unknown)
LocalPath string // Local file path (set after download or for local sources)
ContentType string // MIME type (if known)
ExcludeURL bool // If true, don't include URL in event (use Blossom URL only)
}
Asset represents a downloadable APK asset.
func FilterUnsupportedArchitectures ¶
FilterUnsupportedArchitectures removes APK assets that explicitly indicate unsupported architectures (x86, x86_64, etc.) in their filename. Assets without architecture indicators or with supported architectures (arm64-v8a, armeabi-v7a) are kept.
type CacheClearer ¶
type CacheClearer interface {
// ClearCache removes any cached release data.
ClearCache() error
}
CacheClearer is an optional interface for sources that support cache clearing. Sources that cache release data (like GitHub with ETags) should implement this to allow clearing the cache when publishing fails.
type CacheCommitter ¶
type CacheCommitter interface {
// CommitCache persists the pending cache data to disk.
// Should be called after successful publishing.
CommitCache() error
}
CacheCommitter is an optional interface for sources that support deferred cache commits. Sources like GitHub store cache data in memory during fetch, then commit to disk only after successful publishing via CommitCache().
type CacheSkipper ¶ added in v0.4.3
type CacheSkipper interface {
SetSkipCache(bool)
}
CacheSkipper is an optional interface for sources that support bypassing their ETag/version cache. Used as a fallback when ErrNotModified is returned but no cached release is available — the workflow retries with the cache skipped.
type CachedReleaseProvider ¶ added in v0.4.1
type CachedReleaseProvider interface {
GetCachedRelease() *Release
}
CachedReleaseProvider is an optional interface for sources that can return a previously cached release. Used when FetchLatestRelease returns ErrNotModified so the workflow can proceed with the cached data instead of aborting.
type DownloadProgress ¶
type DownloadProgress func(downloaded, total int64)
DownloadProgress is called during downloads to report progress.
type FDroid ¶
type FDroid struct {
SkipCache bool
// contains filtered or unexported fields
}
FDroid implements Source for F-Droid compatible repositories. Supports: f-droid.org, IzzyOnDroid (apt.izzysoft.de), and other F-Droid repos.
func (*FDroid) CommitCache ¶ added in v0.4.2
CommitCache persists the pending cache to disk after successful publishing.
func (*FDroid) Download ¶
func (f *FDroid) Download(ctx context.Context, asset *Asset, destDir string, progress DownloadProgress) (string, error)
Download downloads an APK from F-Droid. Uses a download cache to avoid re-downloading the same file.
func (*FDroid) FetchLatestRelease ¶
FetchLatestRelease fetches the latest release from an F-Droid compatible repository. For repos with a per-package API (f-droid.org), uses a lightweight API call. For others (IzzyOnDroid), fetches the shared index with ETag caching to avoid re-downloading the full 14–50 MB file when unchanged.
func (*FDroid) FetchMetadata ¶
FetchMetadata fetches app metadata from the repository's metadata source.
func (*FDroid) GetCachedRelease ¶ added in v0.4.2
GetCachedRelease returns the cached release for this package if available.
func (*FDroid) RepoInfo ¶
func (f *FDroid) RepoInfo() *config.FDroidRepoInfo
RepoInfo returns the repository information.
func (*FDroid) SetSkipCache ¶ added in v0.4.3
SetSkipCache implements CacheSkipper.
type GitHub ¶
type GitHub struct {
SkipCache bool // Set to true to bypass ETag cache (--overwrite-release)
IncludePreReleases bool // Set to true to include pre-releases (--pre-release)
// contains filtered or unexported fields
}
GitHub implements Source for GitHub releases.
func (*GitHub) ClearCache ¶
ClearCache removes the cached release data. This should be called when publishing fails so the next run can retry.
func (*GitHub) CommitCache ¶
CommitCache saves the pending cache to disk. This should be called after successful publishing to persist the ETag.
func (*GitHub) Download ¶
func (g *GitHub) Download(ctx context.Context, asset *Asset, destDir string, progress DownloadProgress) (string, error)
Download downloads an asset from GitHub. Uses a download cache to avoid re-downloading the same file.
func (*GitHub) FetchLatestRelease ¶
FetchLatestRelease fetches the latest release from GitHub that contains valid APKs. First tries /releases/latest (single request, fast path). If that release is a draft, a pre-release (when not opted in), or carries no valid APKs, falls back to scanning the most recent releases list to find one that qualifies. Uses conditional requests (ETag/If-None-Match) on the fast path to reduce rate limit usage. Returns ErrNotModified if the latest release hasn't changed since the last check. Set SkipCache to true to bypass the ETag check and always fetch fresh data.
func (*GitHub) GetCachedRelease ¶
GetCachedRelease returns the cached release if available.
func (*GitHub) SetSkipCache ¶ added in v0.4.3
SetSkipCache implements CacheSkipper.
type GitLab ¶
type GitLab struct {
// contains filtered or unexported fields
}
GitLab implements Source for GitLab releases. Supports both gitlab.com and self-hosted GitLab instances.
func (*GitLab) Download ¶
func (g *GitLab) Download(ctx context.Context, asset *Asset, destDir string, progress DownloadProgress) (string, error)
Download downloads an asset from GitLab. Uses a download cache to avoid re-downloading the same file.
func (*GitLab) FetchLatestRelease ¶
FetchLatestRelease fetches the latest release from GitLab that contains valid APKs. Iterates through up to 10 releases to find one with APK assets (for repos that publish desktop and mobile releases separately).
type Gitea ¶
type Gitea struct {
IncludePreReleases bool // Set to true to include pre-releases (--pre-release)
// contains filtered or unexported fields
}
Gitea implements Source for Gitea/Forgejo/Codeberg releases. This covers any Gitea-compatible forge (Gitea, Forgejo, Codeberg, etc.)
func (*Gitea) Download ¶
func (g *Gitea) Download(ctx context.Context, asset *Asset, destDir string, progress DownloadProgress) (string, error)
Download downloads an asset from a Gitea-compatible forge. Uses a download cache to avoid re-downloading the same file.
func (*Gitea) FetchLatestRelease ¶
FetchLatestRelease fetches the latest release from a Gitea-compatible forge that contains valid APKs. Iterates through up to 10 releases to find one with APK assets (for repos that publish desktop and mobile releases separately).
type Local ¶
type Local struct {
// contains filtered or unexported fields
}
Local implements Source for local filesystem APKs.
func NewLocalWithBase ¶
NewLocalWithBase creates a new local source with a base directory for relative paths.
func (*Local) Download ¶
func (l *Local) Download(ctx context.Context, asset *Asset, destDir string, progress DownloadProgress) (string, error)
Download returns the local path (no download needed for local files).
func (*Local) FetchLatestRelease ¶
FetchLatestRelease finds local APK files matching the pattern.
type MetadataError ¶
MetadataError represents a non-fatal error when fetching metadata from a source.
func (*MetadataError) Error ¶
func (e *MetadataError) Error() string
type MetadataFetcher ¶
type MetadataFetcher struct {
PackageID string // App package ID (e.g., "com.example.app") - set from APK parsing
APKName string // App name from APK - takes priority over metadata sources
// contains filtered or unexported fields
}
MetadataFetcher fetches metadata from external sources.
func NewMetadataFetcher ¶
func NewMetadataFetcher(cfg *config.Config) *MetadataFetcher
NewMetadataFetcher creates a new metadata fetcher.
func NewMetadataFetcherWithPackageID ¶
func NewMetadataFetcherWithPackageID(cfg *config.Config, packageID string) *MetadataFetcher
NewMetadataFetcherWithPackageID creates a new metadata fetcher with a known package ID.
func (*MetadataFetcher) FetchMetadata ¶
func (f *MetadataFetcher) FetchMetadata(ctx context.Context, sources []string) error
FetchMetadata fetches metadata from the specified sources and merges into config. Sources can be: "github", "gitlab", "fdroid", "playstore" Only empty fields in config are populated (existing values are preserved). Returns a MetadataResult containing any non-fatal errors from individual sources.
func (*MetadataFetcher) FetchMetadataWithResult ¶
func (f *MetadataFetcher) FetchMetadataWithResult(ctx context.Context, sources []string) *MetadataResult
FetchMetadataWithResult fetches metadata and returns detailed results including partial failures.
type MetadataResult ¶
type MetadataResult struct {
// Errors contains non-fatal errors from individual sources.
// The fetch continues even if some sources fail.
Errors []*MetadataError
}
MetadataResult contains the result of fetching metadata from multiple sources.
func (*MetadataResult) HasErrors ¶
func (r *MetadataResult) HasErrors() bool
HasErrors returns true if any metadata sources failed.
type Options ¶
type Options struct {
// BaseDir is the base directory for resolving relative paths.
// Typically the directory containing the config file.
BaseDir string
// SkipCache bypasses ETag cache for GitHub sources (--overwrite-release).
SkipCache bool
// IncludePreReleases includes pre-releases when fetching the latest release (--pre-release).
IncludePreReleases bool
}
Options contains options for creating a source.
type ParsedRelease ¶
ParsedRelease contains a release with its parsed APK information.
type PlayStore ¶
type PlayStore struct {
// contains filtered or unexported fields
}
PlayStore provides metadata fetching from Google Play Store.
func NewPlayStore ¶
NewPlayStore creates a new Play Store metadata fetcher.
func (*PlayStore) FetchMetadata ¶
func (p *PlayStore) FetchMetadata(ctx context.Context) (*PlayStoreMetadata, error)
FetchMetadata fetches app metadata from the Google Play Store.
func (*PlayStore) Type ¶
func (p *PlayStore) Type() config.SourceType
Type returns the source type for Play Store.
type PlayStoreMetadata ¶
PlayStoreMetadata contains metadata scraped from the Play Store.
type ProgressReader ¶
type ProgressReader struct {
Reader io.Reader
Total int64
Downloaded int64
OnProgress DownloadProgress
}
Downloader wraps an io.Reader to track download progress.
type Release ¶
type Release struct {
Version string // Version string (e.g., "1.2.3" or "v1.2.3")
TagName string // Git tag name (if applicable)
Changelog string // Release notes/changelog
Assets []*Asset // Available APK assets
PreRelease bool // Whether this is a pre-release
URL string // Release page URL (e.g., https://github.com/user/repo/releases/tag/v1.0)
CreatedAt time.Time // Release creation/publish date (zero if unknown)
}
Release represents a release containing one or more APK assets.
type Source ¶
type Source interface {
// Type returns the source type.
Type() config.SourceType
// FetchLatestRelease fetches the latest release information.
FetchLatestRelease(ctx context.Context) (*Release, error)
// Download downloads an asset and returns the local path.
// For local sources, this may just return the existing path.
// The optional progress callback is called during download.
Download(ctx context.Context, asset *Asset, destDir string, progress DownloadProgress) (string, error)
}
Source is the interface for APK sources.
type StallTimeoutReader ¶ added in v0.3.3
type StallTimeoutReader struct {
Reader io.Reader
Timeout time.Duration
// contains filtered or unexported fields
}
StallTimeoutReader wraps an io.Reader and returns an error if no data is received for the specified duration. Unlike http.Client.Timeout, this only triggers when the download stalls — not after a fixed total time.
type Web ¶
type Web struct {
SkipCache bool // Set to true to bypass version/HTTP cache
// contains filtered or unexported fields
}
Web implements Source for web scraping with version extraction.
func (*Web) CommitCache ¶
CommitCache saves the pending cache to disk. This should be called after successful publishing to persist the cache.
func (*Web) Download ¶
func (w *Web) Download(ctx context.Context, asset *Asset, destDir string, progress DownloadProgress) (string, error)
Download downloads an APK from the web. Uses a download cache to avoid re-downloading the same file.
func (*Web) FetchLatestRelease ¶
FetchLatestRelease fetches the latest release from a web source.
The method supports four modes:
1. Version extraction mode (version + asset_url with {version} template):
- Fetches the URL and extracts version using the configured extractor
- Substitutes {version} in asset_url to get the download URL
- Caches by version - skips if version hasn't changed
2. Asset extraction mode (version + asset extractor):
- Extracts version from page for caching (skips if unchanged)
- Extracts download URL dynamically from page using asset extractor
- Used for sites with dynamic/expiring download URLs (e.g., CDN tokens)
3. Direct URL mode (asset_url only, no version extractor):
- Uses asset_url directly as the download URL
- Uses HTTP caching (ETag/Last-Modified) to detect changes
- Version is extracted from the downloaded APK
4. Direct URL shorthand (release_source: "https://example.com/app.apk"):
- Same as mode 3, but specified as a simple string
func (*Web) GetCachedRelease ¶ added in v0.4.1
GetCachedRelease returns the cached release if available.
func (*Web) SetSkipCache ¶ added in v0.4.3
SetSkipCache implements CacheSkipper.