Help us shape the future of Go! Take the 2026 Go Developer Survey

nzb

package
v0.3.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 3, 2026 License: GPL-3.0 Imports: 13 Imported by: 0

Documentation

Overview

Package nzb parses NZB documents: the XML index of a Usenet post that lists every file, its newsgroups and the message IDs of its segments (articles). Besides the raw structure it derives file names from subjects, classifies files (video, archive volumes, par2, extras), flags obfuscated names and groups archive volumes into ordered sets, which is what the stream engine needs to find the playable file of a release.

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalid = errors.New("nzb: invalid document")

ErrInvalid is returned for documents that are not usable NZBs.

Functions

func IsObfuscated

func IsObfuscated(name string) bool

IsObfuscated reports whether a name carries no information about the content: no extension, a hash/UUID-like base, a long random token, or the "abc.xyz" placeholder some posters use.

func IsPar2Volume

func IsPar2Volume(name string) bool

IsPar2Volume reports whether name is a PAR2 recovery volume ("x.vol03+04.par2") rather than an index file ("x.par2").

func IsVideoExt

func IsVideoExt(ext string) bool

IsVideoExt reports whether ext (without dot, any case) is a video container.

func NameFromSubject

func NameFromSubject(subject string) string

NameFromSubject extracts the file name from a Usenet subject line, e.g.

`"Movie.2024.part01.rar" yEnc (1/50)`                -> Movie.2024.part01.rar
`[01/42] - "Movie.2024.mkv" yEnc (1/1000)`          -> Movie.2024.mkv
`[PRiVATE]-[WtFnZb]-[Movie.2024.mkv]-[1/5] - "" yEnc` -> Movie.2024.mkv
`Movie.2024.r00 (1/50)`                             -> Movie.2024.r00

Types

type File

type File struct {
	Index   int // position in NZB.Files
	Poster  string
	Date    time.Time
	Subject string
	Groups  []string
	// Segments sorted by Number, de-duplicated: the first occurrence of a
	// number wins, later message-IDs for it become its Alternates.
	Segments []Segment

	// Name is the file name derived from the subject (may be obfuscated).
	Name string
	// Obfuscated reports that Name looks random (hashes, missing extension),
	// so it says nothing about the content.
	Obfuscated bool
	// Info classifies Name.
	Info FileInfo
	// SubjectIndex / SubjectCount are the "[03/50]" file counter in the
	// subject, 0 when absent. Useful to order obfuscated volumes.
	SubjectIndex int
	SubjectCount int
	// ExpectedSegments is the "(1/N)" segment count in the subject, or 0.
	ExpectedSegments int
	// Duplicates counts repeated segment numbers folded into an earlier
	// segment (as Alternates when the message-ID differs).
	Duplicates int
}

File is one posted file.

func Par2Index

func Par2Index(files []*File) *File

Par2Index returns the PAR2 index file among files: the smallest file classified as PAR2 that is not a recovery volume (preferring one that is not a sample's), or nil. The index holds only metadata packets (file names, sizes, hashes), typically a few KB.

func (*File) Bytes

func (f *File) Bytes() int64

Bytes is the sum of the listed segment sizes. It is the encoded article size, a few percent larger than the decoded file; use it for comparisons.

func (*File) Missing

func (f *File) Missing() []int

Missing returns the segment numbers in 1..SegmentCount() that the NZB does not list.

func (*File) SegmentCount

func (f *File) SegmentCount() int

SegmentCount is the number of part slots the file has: the highest segment number seen or announced by the subject.

type FileInfo

type FileInfo struct {
	Kind Kind
	// Ext is the lower-cased extension of the content: "mkv" for
	// "movie.mkv" and for "movie.mkv.001"; "rar" / "7z" for archives.
	Ext string
	// Volume is the 0-based position of an archive volume in its set
	// (.rar=0, .r00=1, .part01.rar=0, .7z.001=0, .001=0). -1 otherwise.
	Volume int
	// SetName is the lower-cased name shared by every volume of a set, so
	// volumes group by (Kind, SetName). For other files it is the
	// lower-cased name without extension.
	SetName string
	// NewStyle is true for .partNN.rar naming, false for .rar/.rNN.
	NewStyle bool
	// Sample and Extra flag short clips that are not the feature.
	Sample bool
	Extra  bool
}

FileInfo is what a file name says about a posted file.

func Classify

func Classify(name string) FileInfo

Classify interprets a file name (a base name or a path inside an archive).

type Kind

type Kind int

Kind classifies a posted file by its name.

const (
	KindUnknown  Kind = iota
	KindVideo         // a playable container (.mkv, .mp4, ...)
	KindRAR           // a RAR volume (.rar, .r00, .partNN.rar)
	KindSevenZip      // a 7z volume (.7z, .7z.001)
	KindSplit         // a plain split volume (.001, .mkv.001)
	KindPar2
	KindNFO
	KindSFV
	KindSubtitle
	KindImage
	KindOther // known but irrelevant (.txt, .nzb, .srr, .iso, ...)
)

func (Kind) IsArchive

func (k Kind) IsArchive() bool

IsArchive reports whether the kind is a volume of a multi-file set.

func (Kind) String

func (k Kind) String() string

type NZB

type NZB struct {
	// Meta holds <head><meta type="..."> values by lower-cased type.
	Meta map[string][]string
	// Files in document order. Files without any valid segment are dropped.
	Files []*File
}

NZB is a parsed document.

func Parse

func Parse(data []byte) (*NZB, error)

Parse parses an NZB document.

func ParseReader

func ParseReader(r io.Reader) (*NZB, error)

ParseReader parses an NZB document from r.

func (*NZB) ArchiveSets

func (n *NZB) ArchiveSets() []*Set

ArchiveSets groups archive volumes by set and orders them. Sets are returned largest first.

func (*NZB) MetaValue

func (n *NZB) MetaValue(typ string) string

MetaValue returns the first meta value of a type ("title", "name", ...).

func (*NZB) Password

func (n *NZB) Password() string

Password returns the first <meta type="password"> value, if any.

func (*NZB) TotalBytes

func (n *NZB) TotalBytes() int64

TotalBytes sums every file's listed size.

type Segment

type Segment struct {
	Number    int    // 1-based part number
	Bytes     int64  // article size as listed in the NZB (encoded, approximate)
	MessageID string // without angle brackets
	// Alternates are message-IDs of reposts ("fills") of this same part,
	// in NZB order, to try when MessageID is missing everywhere. A repost
	// carries the same yEnc part, so its bytes must land on the same range.
	Alternates []string
}

Segment is one article of a file.

type Set

type Set struct {
	Kind Kind
	// Name is the lower-cased set name shared by the volumes
	// ("movie.2024" for movie.2024.part01.rar, "movie.mkv" for movie.mkv.001).
	Name string
	// NewStyle is true for .partNN.rar sets.
	NewStyle bool
	// Volumes in order; gaps are listed in Missing. The files' Info is left
	// untouched (a part00/.000 set keeps numbering from -1), so grouping the
	// same files again gives the same result and concurrent callers do not
	// write shared files.
	Volumes []*File
	// Missing lists absent 0-based volume numbers below the highest present.
	Missing []int
	// Duplicates are reposted volumes that lost to a larger copy.
	Duplicates []*File
}

Set is the ordered volumes of one archive (RAR, 7z or plain split).

func GroupSets

func GroupSets(files []*File) []*Set

GroupSets groups the archive volumes among files (classified by their Info) into ordered sets, largest first.

func (*Set) Bytes

func (s *Set) Bytes() int64

Bytes sums the listed sizes of the set's volumes.

func (*Set) Complete

func (s *Set) Complete() bool

Complete reports whether no volume is missing (as far as names tell).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL