Downloading Files
Download images and models with customizable path patterns, hash verification, and format detection.
Service Registration
Default:
// Uses system temp directory with minimal patterns
builder.Services.AddCivitaiDownloads();
From Config:
builder.Services.AddCivitaiDownloads(builder.Configuration.GetSection("CivitaiDownloads"));
Programmatic:
builder.Services.AddCivitaiDownloads(options =>
{
options.Images.BaseDirectory = @"C:\Downloads\Images";
options.Images.PathPattern = "{Username}/{Id}.{Extension}";
options.Images.OverwriteExisting = false;
options.Models.BaseDirectory = @"C:\Models";
options.Models.PathPattern = "{ModelType}/{ModelName}/{FileName}";
options.Models.OverwriteExisting = true;
options.Models.VerifyHash = true;
options.Models.HashAlgorithm = HashAlgorithm.Sha256;
});
Download Images
Basic:
// Download an image using configured options
var imageResult = await apiClient.Images
.ExecuteAsync(resultsLimit: 1);
if (imageResult is Result<PagedResult<Image>>.Success imageSuccess)
{
var image = imageSuccess.Data.Items.FirstOrDefault();
if (image is not null)
{
var downloadResult = await downloadService.DownloadAsync(image);
if (downloadResult is Result<DownloadedFile>.Success downloadSuccess)
{
Console.WriteLine($"Downloaded to: {downloadSuccess.Data.FilePath}");
Console.WriteLine($"Size: {downloadSuccess.Data.SizeBytes:N0} bytes");
}
}
}
Custom Directory:
// Download an image to a custom directory
var imageCustomResult = await apiClient.Images
.WhereUsername("Mewyk")
.ExecuteAsync(resultsLimit: 1);
if (imageCustomResult is Result<PagedResult<Image>>.Success customPathSuccess)
{
var image = customPathSuccess.Data.Items.FirstOrDefault();
if (image is not null)
{
var downloadResult = await downloadService.DownloadAsync(
image,
@"D:\CustomImages");
if (downloadResult is Result<DownloadedFile>.Success downloadSuccess)
{
Console.WriteLine($"Downloaded to custom path: {downloadSuccess.Data.FilePath}");
}
}
}
Image Path Tokens
Tokens are replaced by the service at download time:
{Id}, {PostId}, {Username}, {Width}, {Height}, {BaseModel}, {NsfwLevel}, {Date}, {Extension}
Example:
{
"PathPattern": "{BaseModel}/{Username}/{Date}_{Id}.{Extension}"
}
Result: SDXL 1.0/ArtistName/2026-01-15_12345678.png
Download Models
Basic:
// Download a model file (without version context)
var modelFileResult = await apiClient.Models.GetByIdAsync(4201);
if (modelFileResult is Result<Model>.Success modelFileSuccess)
{
var version = modelFileSuccess.Data.ModelVersions?.FirstOrDefault();
var file = version?.Files?.FirstOrDefault(f => f.Primary == true);
if (file is not null)
{
var downloadResult = await downloadService.DownloadAsync(file);
if (downloadResult is Result<DownloadedFile>.Success downloadSuccess)
{
Console.WriteLine($"Downloaded: {downloadSuccess.Data.FilePath}");
Console.WriteLine($"Verified: {downloadSuccess.Data.IsVerified}");
}
}
}
With Version:
// Download a model file with version context for better path organization
var modelVersionResult = await apiClient.Models.GetByIdAsync(4201);
if (modelVersionResult is Result<Model>.Success modelVersionSuccess)
{
var version = modelVersionSuccess.Data.ModelVersions?.FirstOrDefault();
var file = version?.Files?.FirstOrDefault(f => f.Primary == true);
if (file is not null && version is not null)
{
// Providing version enables additional path tokens like {ModelName}, {BaseModel}, etc.
var downloadResult = await downloadService.DownloadAsync(file, version);
if (downloadResult is Result<DownloadedFile>.Success downloadSuccess)
{
Console.WriteLine($"Downloaded: {downloadSuccess.Data.FilePath}");
Console.WriteLine($"Size: {downloadSuccess.Data.SizeBytes:N0} bytes");
Console.WriteLine($"Verified: {downloadSuccess.Data.IsVerified}");
if (downloadSuccess.Data.ComputedHash is not null)
{
Console.WriteLine($"Hash: {downloadSuccess.Data.ComputedHash}");
}
}
else if (downloadResult is Result<DownloadedFile>.Failure downloadFailure)
{
Console.WriteLine($"Download failed: {downloadFailure.Error.Message}");
}
}
}
From URL:
// Download from a raw URL with hash verification
var rawUrl = "https://civitai.com/api/download/models/130072";
var destinationPath = @"C:\Downloads\model.safetensors";
var expectedHash = "abc123def456...";
var urlResult = await downloadService.DownloadAsync(
rawUrl,
destinationPath,
expectedHash,
HashAlgorithm.Sha256);
if (urlResult is Result<DownloadedFile>.Success urlDownloadSuccess)
{
Console.WriteLine($"Downloaded and verified: {urlDownloadSuccess.Data.FilePath}");
}
Model Path Tokens
File tokens: {FileId}, {FileName}, {FileType}, {Format}, {Size}, {Precision}
Version tokens: {VersionId}, {VersionName}, {BaseModel}, {ModelId}, {ModelName}, {ModelType}
Example:
{
"PathPattern": "{ModelType}/{BaseModel}/{ModelName}/{VersionName}/{FileName}"
}
Hash Verification
builder.Services.AddCivitaiDownloads(options =>
{
options.Models.VerifyHash = true;
options.Models.HashAlgorithm = HashAlgorithm.Sha256;
});
Automatically downloads, computes hash, compares against Civitai metadata, and deletes on mismatch.
Verification Result:
var verifyModelResult = await apiClient.Models.GetByIdAsync(4201);
if (verifyModelResult is Result<Model>.Success verifyModelSuccess)
{
var version = verifyModelSuccess.Data.ModelVersions?.FirstOrDefault();
var file = version?.Files?.FirstOrDefault(f => f.Primary == true);
if (file is not null && version is not null)
{
var verifyResult = await downloadService.DownloadAsync(file, version);
if (verifyResult is Result<DownloadedFile>.Success verifySuccess)
{
if (verifySuccess.Data.IsVerified)
{
Console.WriteLine($"Verified hash: {verifySuccess.Data.ComputedHash}");
}
else
{
Console.WriteLine("Hash verification was not performed");
}
}
}
}
File Format Detection
// Detect from file path
var format = await FileFormatDetector.DetectFormatAsync(filePath);
Console.WriteLine($"Detected format: {format}"); // "png", "jpg", "mp4", etc.
// Detect from stream
await using var formatStream = File.OpenRead(filePath);
var formatFromStream = await FileFormatDetector.DetectFormatAsync(formatStream);
// Detect from bytes
var header = new byte[16];
var bytesRead = await formatStream.ReadAsync(header.AsMemory());
var formatFromBytes = FileFormatDetector.DetectFormat(header.AsSpan(0, bytesRead));
Supported: PNG, JPEG, GIF, WebP, AVIF, HEIC, MP4, WebM
Error Handling
Codes: ImageUrlMissing, DownloadUrlMissing, HashVerificationFailed, HashComputationFailed
var errorModelResult = await apiClient.Models.GetByIdAsync(4201);
if (errorModelResult is Result<Model>.Success errorModelSuccess)
{
var version = errorModelSuccess.Data.ModelVersions?.FirstOrDefault();
var file = version?.Files?.FirstOrDefault(f => f.Primary == true);
if (file is not null && version is not null)
{
var errorResult = await downloadService.DownloadAsync(file, version);
switch (errorResult)
{
case Result<DownloadedFile>.Success success:
Console.WriteLine($"Downloaded: {success.Data.FilePath}");
break;
case Result<DownloadedFile>.Failure { Error.Code: ErrorCode.HashVerificationFailed } failure:
Console.WriteLine($"Corrupted download: {failure.Error.Message}");
break;
case Result<DownloadedFile>.Failure { Error.Code: ErrorCode.IoError } failure:
Console.WriteLine($"File exists: {failure.Error.Message}");
break;
case Result<DownloadedFile>.Failure failure:
Console.WriteLine($"Download failed: {failure.Error.Message}");
break;
}
}
}
Configuration
ImageDownloadOptions:
BaseDirectory- Root directoryPathPattern- Pattern with tokensOverwriteExisting- Replace files
ModelDownloadOptions:
BaseDirectory- Root directoryPathPattern- Pattern with tokensOverwriteExisting- Replace filesVerifyHash- Verify after downloadHashAlgorithm- Algorithm for verification