### Install TorznabClient via NuGet Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Use the .NET CLI to add the package to your project. ```bash dotnet add package TorznabClient ``` -------------------------------- ### Configure Polly Resilience Policies Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Integrate Polly for HTTP retry logic and fault handling. This example adds a retry policy to the Jackett client's HttpClientBuilder. ```csharp using Polly; using Polly.Extensions.Http; builder.Services.AddJackettClient( builder.Configuration, configureClientBuilder: (IHttpClientBuilder clientBuilder) => { clientBuilder.AddPolicyHandler(GetRetryPolicy()); }); static IAsyncPolicy GetRetryPolicy() { return HttpPolicyExtensions .HandleTransientHttpError() .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); } ``` -------------------------------- ### Get Indexers from Jackett Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Retrieve a list of available indexers from Jackett. Optionally filter to only include configured indexers or override the API key for a specific request. ```csharp var client = host.Services.GetRequiredService(); // Get all indexers List allIndexers = await client.GetIndexersAsync(); // Get only configured indexers List configuredIndexers = await client.GetIndexersAsync(configured: true); // Override API key for this request List indexers = await client.GetIndexersAsync( apiKey: "different_api_key", configured: true); foreach (var indexer in configuredIndexers) { Console.WriteLine($"ID: {indexer.Id}"); Console.WriteLine($"Title: {indexer.Title}"); Console.WriteLine($"Description: {indexer.Description}"); Console.WriteLine($"Type: {indexer.Type}"); Console.WriteLine($"Configured: {indexer.Configured}"); Console.WriteLine(); } ``` -------------------------------- ### Customize Torznab and Jackett clients Source: https://github.com/borisgerretzen/torznabclient/blob/main/README.md Demonstrates how to use custom configuration sections, configure HttpClient, and apply Polly policies. ```csharp // Specify a custom section name. builder.Services.AddTorznabClient(builder.Configuration, sectionName: "CustomSectionName"); // Customize the HttpClient builder.Services.AddTorznabClient(builder.Configuration, configureClient: (IServiceProvider provider, HttpClient httpClient) => { httpClient.Timeout = TimeSpan.FromSeconds(10); httpClient.DefaultRequestHeaders.Add("User-Agent", "TorznabClient.Demo"); }); // Use a Polly policy builder.Services.AddTorznabClient(builder.Configuration, configureClientBuilder: (IHttpClientBuilder clientBuilder) => { clientBuilder.AddPolicyHandler(GetRetryPolicy()); }); static IAsyncPolicy GetRetryPolicy() { return HttpPolicyExtensions .HandleTransientHttpError() .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); } ``` -------------------------------- ### Register and use JackettClient Source: https://github.com/borisgerretzen/torznabclient/blob/main/README.md Configures the Jackett client via dependency injection and retrieves indexers. ```csharp using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using TorznabClient; var builder = Host.CreateApplicationBuilder(); // Load configuration, in this case from an in-memory collection. var configurationBuilder = new ConfigurationBuilder(); configurationBuilder.AddInMemoryCollection(new Dictionary { ["JackettClient:Url"] = "http://localhost:9117/", // Note, only put the base url here. ["JackettClient:ApiKey"] = "your_api_key" }); builder.Configuration.AddConfiguration(configurationBuilder.Build()); // Add Torznab client to the service collection. builder.Services.AddJackettClient(builder.Configuration); var host = builder.Build(); var client = host.Services.GetRequiredService(); var indexers = await client.GetIndexersAsync(); Console.WriteLine(indexers); ``` -------------------------------- ### Iterate and Process Torznab Releases Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Demonstrates how to iterate through a list of TorznabReleases and access their basic properties, download URL, and extended attributes like seeders and leechers. ```csharp // Working with releases foreach (var release in results.Channel?.Releases ?? []) { // Basic properties Console.WriteLine($"Title: {release.Title}"); Console.WriteLine($"Size: {release.Size / 1_048_576.0:F2} MB"); Console.WriteLine($"Published: {release.PubDate:yyyy-MM-dd HH:mm}"); // Download URL from enclosure var downloadUrl = release.Enclosure?.Url; // Extended attributes (seeders, peers, etc.) var seeders = release.Attributes.FirstOrDefault(a => a.Name == "seeders")?.Value ?? "0"; var leechers = release.Attributes.FirstOrDefault(a => a.Name == "peers")?.Value ?? "0"; Console.WriteLine($"S/L: {seeders}/{leechers}"); } ``` -------------------------------- ### Register and use JackettClient Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Registers the IJackettClient with the dependency injection container and demonstrates retrieving indexers. ```csharp using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using TorznabClient; using TorznabClient.Jackett; var builder = Host.CreateApplicationBuilder(); // Configure from appsettings.json or in-memory collection var configurationBuilder = new ConfigurationBuilder(); configurationBuilder.AddInMemoryCollection(new Dictionary { ["JackettClient:Url"] = "http://localhost:9117/", // Base URL only ["JackettClient:ApiKey"] = "your_api_key_here" }); builder.Configuration.AddConfiguration(configurationBuilder.Build()); // Register the Jackett client builder.Services.AddJackettClient(builder.Configuration); var host = builder.Build(); // Resolve and use the client var client = host.Services.GetRequiredService(); var indexers = await client.GetIndexersAsync(); foreach (var indexer in indexers) { Console.WriteLine($"Indexer: {indexer.Title} (ID: {indexer.Id}, Configured: {indexer.Configured})"); } ``` -------------------------------- ### Register and use TorznabClient Source: https://github.com/borisgerretzen/torznabclient/blob/main/README.md Configures the Torznab client via dependency injection and retrieves capabilities. ```csharp using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using TorznabClient; var builder = Host.CreateApplicationBuilder(); // Load configuration, in this case from an in-memory collection. var configurationBuilder = new ConfigurationBuilder(); configurationBuilder.AddInMemoryCollection(new Dictionary { ["TorznabClient:Url"] = "http://localhost:9117/api/v2.0/indexers/all/results/torznab", ["TorznabClient:ApiKey"] = "your_api_key" }); builder.Configuration.AddConfiguration(configurationBuilder.Build()); // Add Torznab client to the service collection. builder.Services.AddTorznabClient(builder.Configuration); var host = builder.Build(); var client = host.Services.GetRequiredService(); var caps = await client.GetCapsAsync(); Console.WriteLine(caps); ``` -------------------------------- ### Register and use TorznabClient Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Registers the ITorznabClient for direct API access and demonstrates retrieving server capabilities. ```csharp using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using TorznabClient; using TorznabClient.Torznab; var builder = Host.CreateApplicationBuilder(); // Configure with full Torznab endpoint URL var configurationBuilder = new ConfigurationBuilder(); configurationBuilder.AddInMemoryCollection(new Dictionary { ["TorznabClient:Url"] = "http://localhost:9117/api/v2.0/indexers/all/results/torznab", ["TorznabClient:ApiKey"] = "your_api_key_here" }); builder.Configuration.AddConfiguration(configurationBuilder.Build()); // Register the Torznab client builder.Services.AddTorznabClient(builder.Configuration); var host = builder.Build(); // Resolve and use the client var client = host.Services.GetRequiredService(); var caps = await client.GetCapsAsync(); Console.WriteLine($"Server: {caps.Server}"); Console.WriteLine($"Categories: {caps.Categories.Count}"); foreach (var category in caps.Categories) { Console.WriteLine($" - {category.Name} (ID: {category.Id})"); } ``` -------------------------------- ### Configure TorznabClient in Background Service Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Sets up dependency injection for TorznabClient and registers a background service. This is the entry point for using the client in a long-running application. ```csharp // Program.cs await Host.CreateDefaultBuilder(args) .ConfigureServices((context, services) => { services.AddHostedService(); services.AddJackettClient(context.Configuration); }) .RunConsoleAsync(); ``` -------------------------------- ### Perform General Search with SearchAsync Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Executes a general search query on the Torznab endpoint and processes the returned RSS results. ```csharp var client = host.Services.GetRequiredService(); TorznabRss results = await client.SearchAsync( query: "linux mint", limit: 50, categories: new[] { 4000 }, maxAge: 60, minSize: 500_000_000, sort: "seeders_desc"); Console.WriteLine($"Channel: {results.Channel?.Title}"); Console.WriteLine($"Description: {results.Channel?.Description}"); Console.WriteLine($"Total Releases: {results.Channel?.Releases.Count}"); foreach (var release in results.Channel?.Releases ?? []) { Console.WriteLine($"Title: {release.Title}"); Console.WriteLine($"GUID: {release.Guid}"); Console.WriteLine($"Size: {release.Size} bytes"); Console.WriteLine($"Published: {release.PubDate}"); Console.WriteLine($"Description: {release.Description}"); Console.WriteLine($"Categories: {string.Join(", ", release.Categories)}"); if (release.Enclosure != null) { Console.WriteLine($"Download URL: {release.Enclosure.Url}"); Console.WriteLine($"Content Type: {release.Enclosure.Type}"); Console.WriteLine($"Length: {release.Enclosure.Length}"); } Console.WriteLine(); } ``` -------------------------------- ### Customize HttpClient settings Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Configures the underlying HttpClient with custom timeouts and headers during registration. ```csharp builder.Services.AddJackettClient( builder.Configuration, configureClient: (IServiceProvider provider, HttpClient httpClient) => { httpClient.Timeout = TimeSpan.FromSeconds(30); httpClient.DefaultRequestHeaders.Add("User-Agent", "MyTorrentApp/1.0"); }); ``` -------------------------------- ### Retrieve Indexer Capabilities with GetCapsAsync Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Fetches metadata about the indexer, including supported categories, limits, and search capabilities. ```csharp var client = host.Services.GetRequiredService(); TorznabCaps caps = await client.GetCapsAsync(); // Server information Console.WriteLine($"Server Version: {caps.Server}"); // Limits Console.WriteLine($"Default results: {caps.Limits}"); // Categories Console.WriteLine("Supported Categories:"); foreach (var category in caps.Categories) { Console.WriteLine($" {category.Id}: {category.Name}"); foreach (var subcat in category.Subcats) { Console.WriteLine($" {subcat.Id}: {subcat.Name}"); } } // Search capabilities Console.WriteLine($"Searching: {caps.Searching}"); // Override URL for this request var capsFromOther = await client.GetCapsAsync( url: "http://other-server:9117/api/v2.0/indexers/specific/results/torznab"); ``` -------------------------------- ### Search Movies with IJackettClient Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Demonstrates searching for movies using title, IMDb ID, or genre via the IJackettClient interface. ```csharp var client = host.Services.GetRequiredService(); // Search by movie title await foreach (var result in client.MovieSearchAsync( query: "Inception", categories: new[] { 2000, 2010, 2020 }, // Movie categories maxAge: 180)) { if (result.IsSuccess) { foreach (var release in result.Result!.Channel?.Releases ?? []) { Console.WriteLine($"Title: {release.Title}"); Console.WriteLine($"Link: {release.Link}"); } } } // Search by IMDb ID for exact matching await foreach (var result in client.MovieSearchAsync( imdbId: "tt1375666", // Inception IMDb ID extended: true)) { // Process results } // Search by genre await foreach (var result in client.MovieSearchAsync( genre: "Sci-Fi", limit: 100, maxAge: 30)) { // Process results } ``` -------------------------------- ### Implement Background Torrent Search Service Source: https://context7.com/borisgerretzen/torznabclient/llms.txt A background service that periodically searches for torrents using TorznabClient. It retrieves indexer information, performs searches, and logs results. Ensure proper cancellation tokens are used for graceful shutdown. ```csharp // TorrentSearchService.cs public class TorrentSearchService( IJackettClient client, ILogger logger) : BackgroundService { protected override async Task ExecuteAsync(CancellationToken stoppingToken) { // Get available indexers var indexers = await client.GetIndexersAsync(configured: true); var indexerIds = indexers.Select(i => i.Id!).ToList(); logger.LogInformation("Found {Count} configured indexers", indexers.Count); // Search across all indexers await foreach (var result in client.SearchAsync( query: "doctor who", indexers: indexerIds, limit: 50, maxAge: 7).WithCancellation(stoppingToken)) { if (result.IsError) { logger.LogWarning(result.Error, "Search failed for an indexer"); continue; } var channel = result.Result!.Channel; logger.LogInformation( "Found {Count} results from {Indexer}", channel?.Releases.Count ?? 0, channel?.Title); foreach (var release in channel?.Releases ?? []) { logger.LogDebug( " {Title} - {Size}MB", release.Title, release.Size / 1_000_000); } } } } ``` -------------------------------- ### Configure custom section names Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Overrides the default configuration section name for client registration. ```csharp // Use a custom section name instead of the default builder.Services.AddJackettClient(builder.Configuration, sectionName: "MyCustomJackett"); builder.Services.AddTorznabClient(builder.Configuration, sectionName: "MyCustomTorznab"); ``` -------------------------------- ### ITorznabClient API Source: https://context7.com/borisgerretzen/torznabclient/llms.txt API endpoints for interacting with a Torznab indexer. ```APIDOC ## ITorznabClient API ### GetCapsAsync #### Description Retrieves capabilities and metadata about the Torznab indexer, including supported search modes, categories, and limits. #### Method GET #### Endpoint /api/indexers/torznab/caps #### Parameters ##### Query Parameters - **url** (string) - Optional - Override URL for this request. #### Request Example ```csharp var client = host.Services.GetRequiredService(); TorznabCaps caps = await client.GetCapsAsync(); // Server information Console.WriteLine($"Server Version: {caps.Server}"); // Limits Console.WriteLine($"Default results: {caps.Limits}"); // Categories Console.WriteLine("Supported Categories:"); foreach (var category in caps.Categories) { Console.WriteLine($" {category.Id}: {category.Name}"); foreach (var subcat in category.Subcats) { Console.WriteLine($" {subcat.Id}: {subcat.Name}"); } } // Search capabilities Console.WriteLine($"Searching: {caps.Searching}"); // Override URL for this request var capsFromOther = await client.GetCapsAsync( url: "http://other-server:9117/api/v2.0/indexers/specific/results/torznab"); ``` #### Response ##### Success Response (200) - **Server** (string) - The server version. - **Limits** (int) - Default results limit. - **Categories** (array) - Supported categories. - **Id** (int) - Category ID. - **Name** (string) - Category name. - **Subcats** (array) - Subcategories. - **Id** (int) - Subcategory ID. - **Name** (string) - Subcategory name. - **Searching** (bool) - Indicates if searching is supported. ##### Response Example ```json { "Server": "1.0", "Limits": 100, "Categories": [ { "Id": 1000, "Name": "Movies", "Subcats": [ { "Id": 1001, "Name": "HD Movies" } ] } ], "Searching": true } ``` ### SearchAsync #### Description Performs a general search on the Torznab endpoint. Returns a single `TorznabRss` result. #### Method GET #### Endpoint /api/indexers/torznab/results #### Parameters ##### Query Parameters - **query** (string) - Required - The search query. - **limit** (int) - Optional - The maximum number of results to return. - **categories** (int[]) - Optional - An array of category IDs to filter results. - **maxAge** (int) - Optional - Maximum age of the releases in days. - **minSize** (long) - Optional - Minimum size of the releases in bytes. - **sort** (string) - Optional - The sorting order (e.g., "seeders_desc"). #### Request Example ```csharp var client = host.Services.GetRequiredService(); TorznabRss results = await client.SearchAsync( query: "linux mint", limit: 50, categories: new[] { 4000 }, maxAge: 60, minSize: 500_000_000, sort: "seeders_desc"); Console.WriteLine($"Channel: {results.Channel?.Title}"); Console.WriteLine($"Description: {results.Channel?.Description}"); Console.WriteLine($"Total Releases: {results.Channel?.Releases.Count}"); foreach (var release in results.Channel?.Releases ?? []) { Console.WriteLine($"Title: {release.Title}"); Console.WriteLine($"GUID: {release.Guid}"); Console.WriteLine($"Size: {release.Size} bytes"); Console.WriteLine($"Published: {release.PubDate}"); Console.WriteLine($"Description: {release.Description}"); Console.WriteLine($"Categories: {string.Join(", ", release.Categories)}"); if (release.Enclosure != null) { Console.WriteLine($"Download URL: {release.Enclosure.Url}"); Console.WriteLine($"Content Type: {release.Enclosure.Type}"); Console.WriteLine($"Length: {release.Enclosure.Length}"); } Console.WriteLine(); } ``` #### Response ##### Success Response (200) - **Channel.Title** (string) - The title of the channel. - **Channel.Description** (string) - The description of the channel. - **Channel.Releases** (array) - A list of releases. - **Title** (string) - The title of the release. - **Guid** (string) - The unique identifier for the release. - **Size** (long) - The size of the release in bytes. - **PubDate** (string) - The publication date of the release. - **Description** (string) - A description of the release. - **Categories** (array) - An array of category names. - **Enclosure.Url** (string) - The download URL. - **Enclosure.Type** (string) - The content type of the enclosure. - **Enclosure.Length** (long) - The length of the enclosure in bytes. ##### Response Example ```json { "Channel": { "Title": "Search Results", "Description": "Results for linux mint", "Releases": [ { "Title": "Linux Mint 21.3", "Guid": "some-guid-123", "Size": 2500000000, "PubDate": "2023-10-26T10:00:00Z", "Description": "A description of the release.", "Categories": ["ISO"], "Enclosure": { "Url": "http://example.com/download/linuxmint.iso", "Type": "application/x-iso9660-image", "Length": 2500000000 } } ] } } ``` ### TvSearchAsync #### Description Searches for TV content with season/episode specificity. Similar to IJackettClient but returns a single result. #### Method GET #### Endpoint /api/indexers/torznab/tvsearch #### Parameters ##### Query Parameters - **query** (string) - Required - The TV show title. - **season** (string) - Optional - The season number. - **episode** (string) - Optional - The episode number. - **categories** (int[]) - Optional - An array of category IDs to filter results. - **tvDbId** (int) - Optional - The TVDB ID of the show. - **extended** (bool) - Optional - Whether to include extended attributes. #### Request Example ```csharp var client = host.Services.GetRequiredService(); TorznabRss results = await client.TvSearchAsync( query: "Game of Thrones", season: "8", episode: "6", categories: new[] { 5000 }, tvDbId: 121361, extended: true); foreach (var release in results.Channel?.Releases ?? []) { Console.WriteLine($"Title: {release.Title}"); Console.WriteLine($"Grabs: {release.Grabs}"); // Extended attributes contain additional metadata var seeders = release.Attributes.FirstOrDefault(a => a.Name == "seeders")?.Value; var peers = release.Attributes.FirstOrDefault(a => a.Name == "peers")?.Value; var infohash = release.Attributes.FirstOrDefault(a => a.Name == "infohash")?.Value; Console.WriteLine($"Seeders: {seeders}, Peers: {peers}"); Console.WriteLine($"InfoHash: {infohash}"); } ``` #### Response ##### Success Response (200) - **Channel.Releases** (array) - A list of TV show releases. - **Title** (string) - The title of the release. - **Grabs** (int) - The number of grabs for the release. - **Attributes** (array) - Additional metadata attributes. - **Name** (string) - The name of the attribute (e.g., "seeders", "peers", "infohash"). - **Value** (string) - The value of the attribute. ##### Response Example ```json { "Channel": { "Title": "Game of Thrones Search", "Releases": [ { "Title": "Game of Thrones S08E06", "Grabs": 150, "Attributes": [ { "Name": "seeders", "Value": "50" }, { "Name": "peers", "Value": "20" }, { "Name": "infohash", "Value": "abcdef1234567890" } ] } ] } } ``` ### MovieSearchAsync (ITorznabClient) #### Description Searches for movie content by query, IMDb ID, or genre. #### Method GET #### Endpoint /api/indexers/torznab/moviesearch #### Parameters ##### Query Parameters - **imdbId** (string) - Optional - The IMDb ID of the movie. - **categories** (int[]) - Optional - An array of category IDs to filter results. - **extended** (bool) - Optional - Whether to include extended attributes. #### Request Example ```csharp var client = host.Services.GetRequiredService(); TorznabRss results = await client.MovieSearchAsync( imdbId: "tt0111161", // The Shawshank Redemption categories: new[] { 2000, 2010, 2020, 2030, 2040, 2050 }, extended: true); foreach (var release in results.Channel?.Releases ?? []) { Console.WriteLine($"Title: {release.Title}"); Console.WriteLine($"Size: {release.Size / 1_000_000_000.0:F2} GB"); Console.WriteLine($"Published: {release.PubDate:yyyy-MM-dd}"); Console.WriteLine($"Link: {release.Link}"); Console.WriteLine($"Download: {release.Enclosure?.Url}"); } ``` #### Response ##### Success Response (200) - **Channel.Releases** (array) - A list of movie releases. - **Title** (string) - The title of the release. - **Size** (long) - The size of the release in bytes. - **PubDate** (string) - The publication date of the release. - **Link** (string) - The link to the release. - **Enclosure.Url** (string) - The download URL. ##### Response Example ```json { "Channel": { "Title": "Movie Search Results", "Releases": [ { "Title": "The Shawshank Redemption (1994)", "Size": 4700000000, "PubDate": "1994-09-23", "Link": "http://example.com/release/shawshank.torrent", "Enclosure": { "Url": "http://example.com/download/shawshank.torrent" } } ] } } ``` ``` -------------------------------- ### SearchAsync Endpoint Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Performs a search across configured indexers. ```APIDOC ## SearchAsync ### Description Searches across multiple indexers for torrents matching the provided query. ### Parameters - **query** (string) - The search term - **indexers** (List) - List of indexer IDs to search - **limit** (int) - Maximum number of results - **maxAge** (int) - Maximum age of results in days ### Response - **IAsyncEnumerable>** - An asynchronous stream of results from the indexers. ``` -------------------------------- ### SearchAsync Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Searches across multiple indexers for torrents matching specific criteria, returning results as an IAsyncEnumerable stream. ```APIDOC ## SearchAsync ### Description Searches across multiple indexers for torrents matching the specified criteria. Returns an IAsyncEnumerable for streaming results as they become available. ### Parameters #### Request Body - **query** (string) - Optional - The search term. - **limit** (int) - Optional - Maximum number of results. - **categories** (int[]) - Optional - Array of category IDs to filter by. - **maxAge** (int) - Optional - Maximum age of the torrent in days. - **minSize** (long) - Optional - Minimum size in bytes. - **maxSize** (long) - Optional - Maximum size in bytes. - **sort** (string) - Optional - Sorting criteria (e.g., "size_desc"). - **indexers** (string[]) - Optional - List of indexer IDs to search. ### Response #### Success Response (200) - **IAsyncEnumerable** - A stream of search results containing channel information and release details. ``` -------------------------------- ### Define TorznabRelease Data Structure Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Represents a single search result item with torrent metadata. Use this record to structure the data for each release found. ```csharp public record TorznabRelease { public string? Title { get; init; } // Release title public string? Guid { get; init; } // Unique identifier public string? Type { get; init; } // Content type public string? Comments { get; init; } // Comments URL public DateTimeOffset? PubDate { get; init; } // Publication date public long? Size { get; init; } // File size in bytes public int? Grabs { get; init; } // Download count public string? Description { get; init; } // Description text public TorznabEnclosure? Enclosure { get; init; } // Download info public string? Link { get; init; } // Details page URL public List Categories { get; init; } // Category IDs public List Attributes { get; init; } // Extended attributes } ``` -------------------------------- ### Handle JackettResult in Async Stream Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Shows the usage pattern for processing results from an asynchronous stream, checking for errors and processing successful results. This pattern is useful for handling paginated or streaming API responses. ```csharp // Usage pattern await foreach (var result in client.SearchAsync(query: "test")) { if (result.IsError) { // Handle error - indexer timeout, invalid response, etc. Console.WriteLine($"Error from indexer: {result.Error?.Message}"); continue; } if (result.IsSuccess) { // Process successful result var releases = result.Result!.Channel?.Releases ?? []; Console.WriteLine($"Found {releases.Count} results"); } } ``` -------------------------------- ### JackettResult Wrapper Source: https://context7.com/borisgerretzen/torznabclient/llms.txt A generic wrapper used to handle success and error states for Jackett operations. ```APIDOC ## JackettResult ### Description A result wrapper for Jackett operations that handles both success and error states gracefully. ### Properties - **Result** (T) - The successful result object - **Error** (Exception) - The exception object if an error occurred - **IsError** (bool) - Returns true if Error is not null - **IsSuccess** (bool) - Returns true if Result is not null ``` -------------------------------- ### GetIndexersAsync Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Retrieves a list of available indexers from Jackett, with options to filter by configuration status or override the API key. ```APIDOC ## GetIndexersAsync ### Description Retrieves the list of available indexers from Jackett. Optionally filter to only configured indexers. ### Parameters #### Query Parameters - **configured** (bool) - Optional - If true, returns only configured indexers. - **apiKey** (string) - Optional - Overrides the default API key for this specific request. ### Response #### Success Response (200) - **List** - A list of indexer objects containing ID, Title, Description, Type, and Configured status. ``` -------------------------------- ### Search for Torrents Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Search across multiple indexers for torrents matching specified criteria. Returns an IAsyncEnumerable for streaming results. Supports filtering by query, limit, categories, age, size, sort order, and specific indexers. ```csharp var client = host.Services.GetRequiredService(); // Get configured indexer IDs var indexers = await client.GetIndexersAsync(configured: true); var indexerIds = indexers.Select(i => i.Id!).ToList(); // Search with multiple parameters await foreach (var result in client.SearchAsync( query: "ubuntu 22.04", limit: 100, categories: new[] { 4000 }, // Software category maxAge: 30, // Last 30 days minSize: 1_000_000_000, // Minimum 1GB maxSize: 10_000_000_000, // Maximum 10GB sort: "size_desc", // Sort by size descending indexers: indexerIds)) { if (result.IsError) { Console.WriteLine($"Error: {result.Error?.Message}"); continue; } var rss = result.Result!; Console.WriteLine($"Indexer: {rss.Channel?.Title}"); Console.WriteLine($"Results: {rss.Channel?.Releases.Count}"); foreach (var release in rss.Channel?.Releases ?? []) { Console.WriteLine($" Title: {release.Title}"); Console.WriteLine($" Size: {release.Size / 1_000_000} MB"); Console.WriteLine($" Published: {release.PubDate}"); Console.WriteLine($" Download: {release.Enclosure?.Url}"); Console.WriteLine(); } } ``` -------------------------------- ### Search TV Content with TvSearchAsync Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Searches for specific TV episodes or seasons, returning extended attributes like seeders and infohashes. ```csharp var client = host.Services.GetRequiredService(); TorznabRss results = await client.TvSearchAsync( query: "Game of Thrones", season: "8", episode: "6", categories: new[] { 5000 }, tvDbId: 121361, extended: true); foreach (var release in results.Channel?.Releases ?? []) { Console.WriteLine($"Title: {release.Title}"); Console.WriteLine($"Grabs: {release.Grabs}"); // Extended attributes contain additional metadata var seeders = release.Attributes.FirstOrDefault(a => a.Name == "seeders")?.Value; var peers = release.Attributes.FirstOrDefault(a => a.Name == "peers")?.Value; var infohash = release.Attributes.FirstOrDefault(a => a.Name == "infohash")?.Value; Console.WriteLine($"Seeders: {seeders}, Peers: {peers}"); Console.WriteLine($"InfoHash: {infohash}"); } ``` -------------------------------- ### Search Movies with ITorznabClient Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Searches for movie content using IMDb ID and returns a single TorznabRss result set. ```csharp var client = host.Services.GetRequiredService(); TorznabRss results = await client.MovieSearchAsync( imdbId: "tt0111161", // The Shawshank Redemption categories: new[] { 2000, 2010, 2020, 2030, 2040, 2050 }, extended: true); foreach (var release in results.Channel?.Releases ?? []) { Console.WriteLine($"Title: {release.Title}"); Console.WriteLine($"Size: {release.Size / 1_000_000_000.0:F2} GB"); Console.WriteLine($"Published: {release.PubDate:yyyy-MM-dd}"); Console.WriteLine($"Link: {release.Link}"); Console.WriteLine($"Download: {release.Enclosure?.Url}"); } ``` -------------------------------- ### MovieSearchAsync (IJackettClient) Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Searches for movies by title, IMDb ID, or genre using the IJackettClient. ```APIDOC ## MovieSearchAsync (IJackettClient) ### Description Searches for movies by title, IMDb ID, or genre. Ideal for finding specific movie releases. ### Method POST (Assumed, based on typical search patterns, actual method not specified) ### Endpoint /api/moviesearch (Assumed, actual endpoint not specified) ### Parameters #### Query Parameters - **query** (string) - Optional - The movie title to search for. - **imdbId** (string) - Optional - The IMDb ID of the movie. - **genre** (string) - Optional - The genre of the movie. - **categories** (int[]) - Optional - An array of category IDs to filter results. - **maxAge** (int) - Optional - Maximum age of the releases in days. ### Request Example ```csharp // Search by movie title await foreach (var result in client.MovieSearchAsync( query: "Inception", categories: new[] { 2000, 2010, 2020 }, // Movie categories maxAge: 180)) { // Process results } // Search by IMDb ID for exact matching await foreach (var result in client.MovieSearchAsync( imdbId: "tt1375666", // Inception IMDb ID extended: true)) { // Process results } // Search by genre await foreach (var result in client.MovieSearchAsync( genre: "Sci-Fi", limit: 100, maxAge: 30)) { // Process results } ``` ### Response #### Success Response (200) - **IsSuccess** (bool) - Indicates if the search was successful. - **Result** (object) - Contains the search results, including a Channel with Releases. - **Channel.Releases** (array) - A list of movie releases. - **Title** (string) - The title of the release. - **Link** (string) - The download link for the release. ``` -------------------------------- ### Search for TV Shows Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Search for TV shows with season and episode filtering. Supports searching by show name, TVDB ID, or TVMaze ID. Results can be filtered by categories, age, and extended attributes. ```csharp var client = host.Services.GetRequiredService(); // Search by show name, season, and episode await foreach (var result in client.TvSearchAsync( query: "Breaking Bad", season: "5", episode: "16", limit: 50, categories: new[] { 5000, 5030, 5040 }, // TV categories maxAge: 365, extended: true)) // Include all extended attributes { if (result.IsSuccess) { foreach (var release in result.Result!.Channel?.Releases ?? []) { Console.WriteLine($"Title: {release.Title}"); Console.WriteLine($"Size: {release.Size}"); Console.WriteLine($"Grabs: {release.Grabs}"); // Access extended attributes foreach (var attr in release.Attributes) { Console.WriteLine($" {attr.Name}: {attr.Value}"); } } } } // Search by TVDB ID await foreach (var result in client.TvSearchAsync( tvDbId: 81189, // Breaking Bad TVDB ID season: "S05", episode: "E16")) { // Process results } // Search by TVMaze ID await foreach (var result in client.TvSearchAsync( tvMazeId: 169, // Breaking Bad TVMaze ID season: "5")) { // Process results } ``` -------------------------------- ### TvSearchAsync Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Searches for TV shows using season and episode filtering, supporting external IDs like TVRage, TVMaze, and TVDB. ```APIDOC ## TvSearchAsync ### Description Searches for TV shows with season and episode filtering. Supports TVRage, TVMaze, and TVDB IDs for precise matching. ### Parameters #### Request Body - **query** (string) - Optional - Show name. - **season** (string) - Optional - Season number. - **episode** (string) - Optional - Episode number. - **tvDbId** (int) - Optional - TVDB ID for the show. - **tvMazeId** (int) - Optional - TVMaze ID for the show. - **limit** (int) - Optional - Maximum number of results. - **categories** (int[]) - Optional - Array of category IDs. - **maxAge** (int) - Optional - Maximum age in days. - **extended** (bool) - Optional - If true, includes extended attributes. ### Response #### Success Response (200) - **IAsyncEnumerable** - A stream of TV search results containing release details and extended attributes. ``` -------------------------------- ### TorznabRelease Model Source: https://context7.com/borisgerretzen/torznabclient/llms.txt Defines the structure of a single torrent search result item returned by the indexer. ```APIDOC ## TorznabRelease Model ### Description Represents a single search result item containing metadata about a torrent release. ### Properties - **Title** (string) - Release title - **Guid** (string) - Unique identifier - **Type** (string) - Content type - **Comments** (string) - Comments URL - **PubDate** (DateTimeOffset) - Publication date - **Size** (long) - File size in bytes - **Grabs** (int) - Download count - **Description** (string) - Description text - **Enclosure** (TorznabEnclosure) - Download info - **Link** (string) - Details page URL - **Categories** (List) - Category IDs - **Attributes** (List) - Extended attributes (e.g., seeders, peers) ``` -------------------------------- ### Define JackettResult Wrapper Source: https://context7.com/borisgerretzen/torznabclient/llms.txt A generic result wrapper for Jackett operations that distinguishes between success and error states. Use this to handle potential exceptions during API calls. ```csharp public record JackettResult(T? Result, Exception? Error) where T : class { public bool IsError => Error != null; public bool IsSuccess => Result != null; } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.