Spottarr.Usenet 4.0.0-beta.1

This is a prerelease version of Spottarr.Usenet.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package Spottarr.Usenet --version 4.0.0-beta.1                
NuGet\Install-Package Spottarr.Usenet -Version 4.0.0-beta.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.0.0-beta.1" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Spottarr.Usenet --version 4.0.0-beta.1                
#r "nuget: Spottarr.Usenet, 4.0.0-beta.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.
// Install Spottarr.Usenet as a Cake Addin
#addin nuget:?package=Spottarr.Usenet&version=4.0.0-beta.1&prerelease

// Install Spottarr.Usenet as a Cake Tool
#tool nuget:?package=Spottarr.Usenet&version=4.0.0-beta.1&prerelease                

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.

Build status

Getting Started

Install Nuget package:

PM> Install-Package 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:

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

Build an article and post to server:

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

NntpArticle 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:

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

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

        // decode the yEnc-encoded article
        using (YencStream yencStream = YencStreamDecoder.Decode(response.Article.Body))
        {
            YencHeader header = yencStream.Header;

            if (!File.Exists(header.FileName))
            {
                // create file and pre-allocate disk space for it
                using (FileStream stream = File.Create(header.FileName))
                {
                    stream.SetLength(header.FileSize);
                }
            }
            using (FileStream 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:

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

NzbBuilder 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 (string fileName in fileNames)
{
    builder.AddFile(fileProvider.GetFileInfo(fileName));
}

NzbDocument nzbDocument = builder.Build();

using (FileStream 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 (NzbFile file in nzbDocument.Files)
{
    // open file stream
    IFileInfo fileInfo = fileProvider.GetFileInfo(file.FileName);
    using (Stream stream = fileInfo.CreateReadStream())
    {
        foreach (NzbSegment segment in file.Segments)
        {
            stream.Position = segment.Offset;

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

            // create article
            NntpArticle 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. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen 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.0.0-beta.2 295 10/19/2024
4.0.0-beta.1 76 10/19/2024