A library for working with Usenet. It offers an NNTP client, an NZB file parser, builder, 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.
$ dotnet add package Spottarr.UsenetA library for working with Usenet. It offers:
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.
Install Nuget package:
dotnet add package Spottarr.Usenet
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();
This project is licensed under the MIT License - see the LICENSE.md file for details.
This project was heavily inspired by Kristian Hellang's work: