Spottarr.Usenet 4.2.1

dotnet add package Spottarr.Usenet --version 4.2.1
                    
NuGet\Install-Package Spottarr.Usenet -Version 4.2.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Spottarr.Usenet" Version="4.2.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Spottarr.Usenet" Version="4.2.1" />
                    
Directory.Packages.props
<PackageReference Include="Spottarr.Usenet" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Spottarr.Usenet --version 4.2.1
                    
#r "nuget: Spottarr.Usenet, 4.2.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#addin nuget:?package=Spottarr.Usenet&version=4.2.1
                    
Install as a Cake Addin
#tool nuget:?package=Spottarr.Usenet&version=4.2.1
                    
Install as a Cake Tool

Usenet

A library for working with Usenet. It offers:

  • an NNTP client
  • an NZB file parser, builder and writer
  • a yEnc encoder and decoder

It is mainly focused on keeping memory usage low. Server responses can be enumerated as they come in. Binary messages will be encoded to yEnc format streaming and yEnc-encoded data will be decoded to binary data streaming.

The NNTP client is compliant with RFC 2980, RFC 3977, RFC 4643 and RFC 6048.

Nuget Nuget Prerelease

Getting Started

Install Nuget package:

dotnet add package Spottarr.Usenet

Examples

Connect to Usenet server:

var client = new NntpClient(new NntpConnection());
await client.ConnectAsync(hostname, port, useSsl);

Authenticate:

client.Authenticate(username, password);

Enable logging:

ILoggerFactory factory = new SomeLoggerFactory();
Usenet.Logger.Factory = factory;

Retrieve article:

var response = client.Article(messageId);
if (response.Success)
{
    foreach (var line in response.Article.Body)
    {
        ...
    }
}

Build an article and post to server:

var messageId = $"{Guid.NewGuid()}@example.net";

var newArticle = new NntpArticleBuilder()
    .SetMessageId(messageId)
    .SetFrom("Randomposter <randomposter@example.net>")
    .SetSubject("Random test post #1")
    .AddGroups("alt.test.clienttest", "alt.test")
    .AddLine("This is a message with id " + messageId)
    .AddLine("with multiple lines")
    .Build();

client.Post(newArticle);

Parse an NZB file, download, decode and write the parts streaming to a file:

var nzbDocument = NzbParser.Parse(File.ReadAllText(nzbPath));

foreach (var file in nzbDocument.Files)
{
    foreach (var segment in file.Segments)
    {
        // retrieve article from Usenet server
        var response = client.Article(segment.MessageId);

        // decode the yEnc-encoded article
        using var yencStream = YencStreamDecoder.Decode(response.Article.Body);

        var header = yencStream.Header;

        if (!File.Exists(header.FileName))
        {
            // create file and pre-allocate disk space for it
            using var stream = File.Create(header.FileName);
            stream.SetLength(header.FileSize);
        }
        else
        {
            using var stream = File.Open(header.FileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);

            // copy incoming parts to file
            stream.Position = header.PartOffset;
            yencStream.CopyTo(stream);
        }
    }
}

Build an NZB document and write to file:

var fileProvider = new PhysicalFileProvider(Path.GetFullPath("testdata"));

var builder = new NzbBuilder()
    .AddGroups("alt.test.clienttest")
    .SetMessageBase("random.local")
    .SetPartSize(50_000)
    .SetPoster("random poster <random.poster@random.com>")
    .AddMetaData("title", "Testing upload Pictures.rar");

foreach (var fileName in fileNames)
{
    builder.AddFile(fileProvider.GetFileInfo(fileName));
}

var nzbDocument = builder.Build();

using var file = File.Open("Pictures.nzb");
using var writer = new StreamWriter(file, UsenetEncoding.Default);

await writer.WriteNzbDocumentAsync(nzbDocument);

Encode the files from an NZB document in yEnc format and upload streaming:

foreach (var file in nzbDocument.Files)
{
    // open file stream
    var fileInfo = fileProvider.GetFileInfo(file.FileName);
    using var stream = fileInfo.CreateReadStream();
    foreach (var segment in file.Segments)
    {
        stream.Position = segment.Offset;

        // encode in yEnc format
        var encodedBody = YencEncoder.Encode(new YencHeader(
            file.FileName, file.Size, 128, segment.Number, file.Segments.Count,
            segment.Size, segment.Offset), stream);

        // create article
        var article = new NntpArticleBuilder()
            .AddGroups(file.Groups)
            .SetMessageId(segment.MessageId)
            .SetFrom(file.Poster)
            .SetSubject(segment.MessageId)
            .SetBody(encodedBody)
            .Build();

        // post article
        client.Post(article);
    }
}

Close connection:

client.Quit();

License

This project is licensed under the MIT License - see the LICENSE.md file for details.

Acknowledgments

This project was heavily inspired by Kristian Hellang's work:

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
4.2.1 169 6/14/2025
4.2.0 290 6/10/2025
4.1.1 82 6/7/2025
4.1.0 307 5/4/2025
4.0.3 79 5/3/2025
4.0.2 150 4/27/2025
4.0.1 136 4/27/2025
4.0.0 181 4/21/2025
4.0.0-beta.3 145 4/21/2025
4.0.0-beta.2 531 10/19/2024
4.0.0-beta.1 97 10/19/2024