Skip to content

Rustbeard86/GitStream

Repository files navigation

GitStream

A lightweight, dependency-free .NET library for downloading GitHub release assets. Simply provide a repository URL and keyword filters to get a file stream, byte array, or download directly to disk.

Features

  • Zero external dependencies - Uses only built-in .NET libraries
  • Source-generation friendly - Clean design suitable for embedding in other assemblies
  • Flexible URL parsing - Accepts various GitHub URL formats
  • Keyword filtering - Find assets by single or multiple keywords
  • Multiple output formats - Stream, byte array, or direct file download
  • CLI test runner - Built via build script for testing

Requirements

  • .NET 10 or later

Installation

Add the project reference or include the source files directly in your solution.

Quick Start

using GitStream;

using var client = new GitStreamClient();

// Download asset to file
await client.DownloadAssetToFileAsync(
    "https://github.com/owner/repo/releases",
    "my-app-win-x64.zip",
    @"C:\Downloads\my-app-win-x64.zip");

Building

Use the included PowerShell build script:

# Clean build artifacts
.\build.ps1 -Clean

# Build library, NuGet package, and CLI test runner
.\build.ps1 -Build

# Clean and build
.\build.ps1 -Clean -Build

Output structure:

release/
??? lib/           # GitStream.dll, GitStream.xml, GitStream.pdb
??? nupkg/         # GitStream.1.0.0.nupkg
??? cli/
    ??? bin/       # GitStream.Cli.exe (test runner)

CLI Test Runner

The build script creates a CLI test runner for testing the library:

# Interactive mode (prompts before download)
.\GitStream.Cli.exe <repo-url> <keyword> [keyword2] ...

# Auto-download mode (no prompts)
.\GitStream.Cli.exe -y <repo-url> <keyword> [keyword2] ...
.\GitStream.Cli.exe --yes <repo-url> <keyword> [keyword2] ...

Examples:

# Find and optionally download an asset
.\GitStream.Cli.exe https://github.com/owner/repo my-app-win-x64.zip

# Auto-download matching asset
.\GitStream.Cli.exe -y https://github.com/owner/repo win-x64 .zip

API Reference

GitStreamClient

The main entry point for interacting with GitHub releases.

Constructors

// Creates client with internal HttpClient (recommended)
public GitStreamClient()

// Uses provided HttpClient (for DI scenarios)
public GitStreamClient(HttpClient httpClient)

Methods

Method Description
GetAssetStreamAsync Returns a Stream for the matching asset
GetAssetBytesAsync Returns a byte[] for the matching asset
DownloadAssetToFileAsync Downloads the asset directly to a file
FindAssetAsync Returns asset metadata without downloading
GetReleasesAsync Gets all releases for a repository
GetLatestReleaseAsync Gets the latest release for a repository
DownloadAssetStreamAsync Downloads from a direct URL

GitHubUrlParser

Static utility for parsing GitHub URLs.

// Parse a GitHub URL
GitHubRepoInfo? info = GitHubUrlParser.Parse("https://github.com/owner/repo");

Models

GitHubRepoInfo

public readonly record struct GitHubRepoInfo(string Owner, string Repo)
{
    public string FullName { get; } // "owner/repo"
}

GitHubRelease

public readonly record struct GitHubRelease(
    string TagName,
    string Name,
    bool Prerelease,
    DateTimeOffset? PublishedAt,
    IReadOnlyList<GitHubReleaseAsset> Assets);

GitHubReleaseAsset

public readonly record struct GitHubReleaseAsset(
    string Name,
    string DownloadUrl,
    long Size,
    string ContentType);

Usage Examples

Get Asset as Stream

using var client = new GitStreamClient();

await using var stream = await client.GetAssetStreamAsync(
    "https://github.com/owner/repo/releases",
    "my-app-win-x64.zip");

if (stream is not null)
{
    // Process the stream
}

Get Asset as Byte Array

using var client = new GitStreamClient();

byte[]? bytes = await client.GetAssetBytesAsync(
    "https://github.com/owner/repo/releases",
    "my-app-win-x64.zip");

if (bytes is not null)
{
    // Use the bytes
}

Download to File

using var client = new GitStreamClient();

bool success = await client.DownloadAssetToFileAsync(
    "https://github.com/owner/repo/releases",
    "my-app-win-x64.zip",
    @"C:\Downloads\my-app-win-x64.zip");

if (success)
{
    Console.WriteLine("Download complete!");
}

Filter by Multiple Keywords

When you need to match multiple patterns in the asset filename:

using var client = new GitStreamClient();

// Asset must contain BOTH "win-x64" AND ".zip"
await using var stream = await client.GetAssetStreamAsync(
    "https://github.com/owner/repo/releases",
    ["win-x64", ".zip"]);

Browse Available Releases

using var client = new GitStreamClient();

var releases = await client.GetReleasesAsync(
    "https://github.com/owner/repo");

foreach (var release in releases)
{
    Console.WriteLine($"{release.TagName} - {release.Name}");
    foreach (var asset in release.Assets)
    {
        Console.WriteLine($"  {asset.Name} ({asset.Size} bytes)");
    }
}

Get Latest Release Info

using var client = new GitStreamClient();

var latest = await client.GetLatestReleaseAsync(
    "https://github.com/owner/repo");

if (latest is { } release)
{
    Console.WriteLine($"Latest: {release.TagName}");
    Console.WriteLine($"Published: {release.PublishedAt}");
    Console.WriteLine($"Assets: {release.Assets.Count}");
}

Find Asset Without Downloading

using var client = new GitStreamClient();

var asset = await client.FindAssetAsync(
    "https://github.com/owner/repo/releases",
    ["my-app-win-x64.zip"]);

if (asset is { } found)
{
    Console.WriteLine($"Found: {found.Name}");
    Console.WriteLine($"Size: {found.Size} bytes");
    Console.WriteLine($"URL: {found.DownloadUrl}");
}

Using with Dependency Injection

// In your DI setup
services.AddHttpClient<GitStreamClient>();

// Or with custom configuration
services.AddHttpClient<GitStreamClient>(client =>
{
    client.Timeout = TimeSpan.FromMinutes(10);
});

Supported URL Formats

The library accepts various GitHub URL formats:

// All of these work:
"https://github.com/owner/repo"
"https://github.com/owner/repo/releases"
"https://github.com/owner/repo.git"
"http://github.com/owner/repo"
"github.com/owner/repo"
"[email protected]:owner/repo.git"

Error Handling

using var client = new GitStreamClient();

try
{
    await using var stream = await client.GetAssetStreamAsync(
        "https://github.com/owner/repo",
        "asset.zip");
    
    if (stream is null)
    {
        Console.WriteLine("Asset not found");
        return;
    }
    
    // Process stream
}
catch (ArgumentException ex)
{
    Console.WriteLine($"Invalid URL: {ex.Message}");
}
catch (HttpRequestException ex)
{
    Console.WriteLine($"Network error: {ex.Message}");
}

Rate Limiting

GitHub API has rate limits for unauthenticated requests (60 requests/hour). For higher limits, configure authentication on the HttpClient:

var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("Bearer", "your-github-token");

using var client = new GitStreamClient(httpClient);

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published