release

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Oct 4, 2025 License: MIT Imports: 28 Imported by: 0

README

go-release

Go library for parsing and checking a scene or p2p release.

Usage

package main

import (
	"encoding/json"
	"fmt"
	"os"

	"github.com/f4n4t/go-release"
)

func main() {
	releaseService := release.NewServiceBuilder().WithSkipMediaInfo(true).Build()
	releaseInfo, err := releaseService.Parse("./Example.Release-Group")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	out, _ := json.MarshalIndent(releaseInfo, "", "\t")

	fmt.Println(string(out))

	if releaseInfo.SfvCount > 0 {
		if err := releaseService.CheckSFV(releaseInfo, true); err != nil {
			fmt.Println("sfv check failed:", err)
			os.Exit(1)
		}
	}

	if releaseInfo.HasExtensions("zip") {
		if err := releaseService.CheckZip(releaseInfo, true); err != nil {
			fmt.Println("zip check failed:", err)
			os.Exit(1)
		}
	}
}

Documentation

Index

Constants

View Source
const (
	Module = "release"
)

Variables

View Source
var (
	// ErrEmptyFolder is the error that Parse will return if the folder is empty.
	ErrEmptyFolder = errors.New("empty folder")

	// ErrFileNotFound is the error returned when a specified file cannot be located.
	ErrFileNotFound = errors.New("file not found")

	// ErrForbiddenFiles is the error that Parse will return on forbidden files.
	ErrForbiddenFiles = errors.New("forbidden files")

	// ErrForbiddenExtension is returned when a file has a prohibited or unsupported extension.
	ErrForbiddenExtension = errors.New("forbidden extension")

	// ErrForbiddenCharacters is the error returned when a file contains prohibited or invalid characters.
	ErrForbiddenCharacters = errors.New("forbidden characters")

	// ErrEmptyFile is the error returned when a file is empty.
	ErrEmptyFile = errors.New("empty file")
)
View Source
var (

	// ForbiddenExtensions holds all the forbidden extensions.
	ForbiddenExtensions = []string{".nzb", ".par2", ".url", ".html", ".srr", ".srs"}

	// PictureExtensions is a struct with known picture extensions.
	PictureExtensions = []string{".jpg", ".jpeg", ".png", ".gif"}

	// AudioExtensions is a struct with known audio extensions.
	AudioExtensions = []string{".mp3", ".aac", ".m4a", ".ogg", ".opus", ".wma", ".ra", ".flac", ".alac", ".ape", ".wv",
		".wav", ".aiff", ".aif", ".pcm", ".au", ".snd"}
)
View Source
var (
	// ErrSfvValidationFailed indicates that an SFV validation process has failed.
	ErrSfvValidationFailed = errors.New("sfv check failed")

	// ErrEmptySfv indicates that the SFV file being processed is empty.
	ErrEmptySfv = errors.New("empty sfv file")

	// ErrInvalidSfv indicates that the provided SFV file is invalid or does not conform to expected formatting rules.
	ErrInvalidSfv = errors.New("invalid sfv file")
)
View Source
var (
	// ErrSrrValidationFailed indicates that the SRR validation process failed due to size or CRC mismatch.
	ErrSrrValidationFailed = errors.New("srr check failed")

	// ErrNoSRRFile indicates that no corresponding SRR file was found on the SRR database.
	ErrNoSRRFile = errors.New("nothing found on srrdb")
)
View Source
var (
	// ErrNoFileCountInDiz represents an error indicating that no file count was found in the .diz metadata.
	ErrNoFileCountInDiz = errors.New("no file count in .diz")

	// ErrNoArchiveInZip represents an error indicating that no archive file was found within the .zip file.
	ErrNoArchiveInZip = errors.New("no archive in .zip")

	// ErrZipValidationFailed represents an error indicating that a check or validation process for a zip file has failed.
	ErrZipValidationFailed = errors.New("zip check failed")
)
View Source
var Regexes = struct {
	Archive, Media, IMDb, CleanTitle, Year, EpisodeSpecial, BadChars, MetaFolders, MetaFiles, Group *regexp.Regexp
}{
	Archive:     regexp.MustCompile(`(?i)\.(rar|r\d{2}|\d{3}|zip|xz|tar|gz)$`),
	Media:       regexp.MustCompile(`(?i)\.(avi|mkv|mpe?g|wm[av]|vob|m2ts|divx|xvid|mp[34]|flac|jpe?g|gif|png|img|iso|aac|m4a|ogg|opus|ra|alac|ape|wv|wav|aiff?|pcm|au|snd)$`),
	IMDb:        regexp.MustCompile(`(?i)imdb.+/(tt\d+)`),
	CleanTitle:  regexp.MustCompile(`(?i)[._-](2160p|1080p|720p|s\d+([ed]\d+)?|e\d+|german|complete|d[vl]|hdr|web(rip)?|internal|ac3d?|unrated|uncut|remastered|stream)[._-].+$`),
	Year:        regexp.MustCompile(`[._ -](\d{4})[._ -]`),
	BadChars:    regexp.MustCompile(`(?i)[^a-z0-9()\[\].\-_+]`),
	MetaFolders: regexp.MustCompile(`(?i)^(sample|subs|proof|cover|extras?|addon)$`),
	MetaFiles:   regexp.MustCompile(`(?i)\.(png|jpe?g|sfv|gif|txt)$`),
	Group:       regexp.MustCompile(`(?i)-([a-z0-9]+(_iNT)?)$`),
}

Regexes is a struct with all compiled regexes used for parsing.

Functions

func MediaInfoBinary

func MediaInfoBinary() (string, error)

MediaInfoBinary checks for the existence of tsmedia or mediainfo-rar in Path.

func ParseLanguage

func ParseLanguage(name string) string

ParseLanguage identifies the language from the release name

Types

type CreatingLibrary

type CreatingLibrary struct {
	Name    string `json:"name"`
	Version string `json:"version"`
	URL     string `json:"url"`
}

type Episode

type Episode struct {
	Number int         `json:"number"`
	Name   string      `json:"name"`
	File   *dtree.Node `json:"-"`
}

Episode represents a single episode in a series.

type ForbiddenFile

type ForbiddenFile struct {
	FullPath string
	Info     *dtree.FileInfo
	Error    error
}

ForbiddenFile represents a forbidden file like empty files or not allowed extension.

type ForbiddenFiles

type ForbiddenFiles []ForbiddenFile

func (*ForbiddenFiles) Names

func (ff *ForbiddenFiles) Names() []string

Names returns only the base names of the forbidden files as a slice.

type Info

type Info struct {
	// ArchiveCount is the total count of archive files (files which matched the archive pattern).
	ArchiveCount int `json:"archive_count"`
	// BiggestFile is the largest file found in the release.
	BiggestFile *dtree.Node `json:"-"`
	// Episodes is a slice with all matched Episodes (only media files).
	Episodes []Episode `json:"episodes"`
	// Extensions is a map with all the found file extensions and their count.
	Extensions map[string]int `json:"extensions"`
	// BaseDir is the base directory path of the release.
	BaseDir string `json:"base_dir"`
	// Root is the root node of the directory tree.
	Root *dtree.Node `json:"-"`
	// ForbiddenFiles is a slice with all the files that are either empty files or folders, have bad chars or matched the ForbiddenExtensions slice.
	ForbiddenFiles ForbiddenFiles `json:"-"`
	// Group is the name of the release group (final part of the release after the -).
	Group string `json:"group"`
	// ImdbID is the parsed IMDB ID from the NFO file.
	ImdbID int `json:"imdb_id"`
	// MediaFiles is a slice with all the media files (files that matched the media pattern).
	MediaFiles MediaFiles `json:"-"`
	// MediaInfo is only generated if mediainfo is found in a path.
	MediaInfo *MediaInfo `json:"-"`
	// MediaInfoJSON contains the raw JSON output from mediainfo.
	MediaInfoJSON []byte `json:"-"`
	// Name is the release name (basename of directory or file without extension).
	Name string `json:"name"`
	// PreInfo is a pointer to the Pre information if something is found.
	PreInfo *Pre `json:"-"`
	// ProductTitle is the title without all the additional meta-tags.
	ProductTitle string `json:"product_title"`
	// ProductYear is the year found in the release name.
	ProductYear int `json:"product_year"`
	// Section is the parsed section category of the release.
	Section Section `json:"section"`
	// SfvCount is the count of all the .sfv files.
	SfvCount int `json:"sfv_count"`
	// Size is the total size of the release in bytes.
	Size int64 `json:"size"`
	// Language is the parsed language tag from the release name.
	Language string `json:"language"`
	// TagResolution is the parsed resolution tag from the release name.
	TagResolution Resolution `json:"tag_resolution"`
	// IsSingleFile is true when the root is a file rather than a directory.
	IsSingleFile bool `json:"single_file"`
	// NFO holds the name and content of an NFO file if one is found.
	NFO *NFOFile `json:"-"`
	// contains filtered or unexported fields
}

Info represents the main struct with all the additional information.

func (*Info) GetPre

func (i *Info) GetPre() (*Pre, bool)

func (*Info) HasAnyExtension

func (rel *Info) HasAnyExtension(extensions ...string) bool

HasAnyExtension checks if any of the given extensions are found.

func (*Info) HasAnyLanguage

func (rel *Info) HasAnyLanguage(languages ...string) bool

HasAnyLanguage checks if any of the given languages are found.

func (*Info) HasExtensions

func (rel *Info) HasExtensions(extensions ...string) bool

HasExtensions checks if all the given extensions are found.

func (*Info) HasGermanLanguage

func (rel *Info) HasGermanLanguage() bool

HasGermanLanguage checks if release has german language.

func (*Info) HasMetaFiles

func (rel *Info) HasMetaFiles(ignore ...string) bool

HasMetaFiles checks extensions against Regexes.MetaFiles.

func (*Info) HasNuke

func (i *Info) HasNuke() bool

type Media

type Media struct {
	Ref    string           `json:"@ref"`
	Tracks []MediaInfoTrack `json:"track"`
}

type MediaFiles added in v0.3.0

type MediaFiles []*dtree.Node

func (MediaFiles) GetByExtensions added in v0.3.0

func (mf MediaFiles) GetByExtensions(extensions ...string) []*dtree.Node

type MediaInfo

type MediaInfo struct {
	CreatingLibrary CreatingLibrary `json:"creatingLibrary"`
	Media           Media           `json:"media"`
}

func GenerateMediaInfo

func GenerateMediaInfo(mediaFile string) ([]byte, *MediaInfo, error)

GenerateMediaInfo calls tsmedia or mediainfo-rar to generate mediainfo output for the biggest file in release. returns the JSON output and MediaInfo, potentially an error.

func (*MediaInfo) GetAttachmentNames

func (m *MediaInfo) GetAttachmentNames(extensions ...string) []string

GetAttachmentNames retrieves the names of attachments filtered by optional file extensions from the collection of tracks. Extensions need to be a list of lowercase file extensions with the leading dot, e.g. ".nfo", ".srt", ".jpg". If no extensions are provided, all attachment names are returned.

func (*MediaInfo) GetNearestResolution

func (m *MediaInfo) GetNearestResolution() Resolution

func (*MediaInfo) HasAnyLanguage

func (m *MediaInfo) HasAnyLanguage(languages ...string) bool

HasAnyLanguage checks if any audio tracks in the collection match the specified languages (case-insensitive).

type MediaInfoTrack

type MediaInfoTrack struct {
	Type                           string              `json:"@type"`
	UniqueID                       string              `json:"UniqueID"`
	VideoCount                     string              `json:"VideoCount,omitempty"`
	AudioCount                     string              `json:"AudioCount,omitempty"`
	TextCount                      string              `json:"TextCount,omitempty"`
	Format                         string              `json:"Format"`
	FormatVersion                  string              `json:"Format_Version,omitempty"`
	FileSize                       string              `json:"FileSize,omitempty"`
	Duration                       string              `json:"Duration"`
	OverallBitRate                 string              `json:"OverallBitRate,omitempty"`
	FrameRate                      string              `json:"FrameRate"`
	FrameCount                     string              `json:"FrameCount"`
	StreamSize                     string              `json:"StreamSize"`
	IsStreamable                   string              `json:"IsStreamable,omitempty"`
	EncodedDate                    string              `json:"Encoded_Date,omitempty"`
	EncodedApplication             string              `json:"Encoded_Application,omitempty"`
	EncodedLibrary                 string              `json:"Encoded_Library,omitempty"`
	StreamOrder                    string              `json:"StreamOrder,omitempty"`
	ID                             string              `json:"ID,omitempty"`
	FormatProfile                  string              `json:"Format_Profile,omitempty"`
	FormatLevel                    string              `json:"Format_Level,omitempty"`
	FormatSettingsCABAC            string              `json:"Format_Settings_CABAC,omitempty"`
	FormatSettingsRefFrames        string              `json:"Format_Settings_RefFrames,omitempty"`
	CodecID                        string              `json:"CodecID,omitempty"`
	BitRate                        string              `json:"BitRate,omitempty"`
	Width                          string              `json:"Width,omitempty"`
	Height                         string              `json:"Height,omitempty"`
	StoredHeight                   string              `json:"Stored_Height,omitempty"`
	SampledWidth                   string              `json:"Sampled_Width,omitempty"`
	SampledHeight                  string              `json:"Sampled_Height,omitempty"`
	PixelAspectRatio               string              `json:"PixelAspectRatio,omitempty"`
	DisplayAspectRatio             string              `json:"DisplayAspectRatio,omitempty"`
	FrameRateMode                  string              `json:"FrameRate_Mode,omitempty"`
	ColorSpace                     string              `json:"ColorSpace,omitempty"`
	ChromaSubsampling              string              `json:"ChromaSubsampling,omitempty"`
	BitDepth                       string              `json:"BitDepth,omitempty"`
	ScanType                       string              `json:"ScanType,omitempty"`
	Delay                          string              `json:"Delay,omitempty"`
	Default                        string              `json:"Default,omitempty"`
	Forced                         string              `json:"Forced,omitempty"`
	ColourDescriptionPresent       string              `json:"colour_description_present,omitempty"`
	ColourDescriptionPresentSource string              `json:"colour_description_present_Source,omitempty"`
	ColourRange                    string              `json:"colour_range,omitempty"`
	ColourRangeSource              string              `json:"colour_range_Source,omitempty"`
	ColourPrimaries                string              `json:"colour_primaries,omitempty"`
	ColourPrimariesSource          string              `json:"colour_primaries_Source,omitempty"`
	TransferCharacteristics        string              `json:"transfer_characteristics,omitempty"`
	TransferCharacteristicsSource  string              `json:"transfer_characteristics_Source,omitempty"`
	MatrixCoefficients             string              `json:"matrix_coefficients,omitempty"`
	MatrixCoefficientsSource       string              `json:"matrix_coefficients_Source,omitempty"`
	TypeOrder                      string              `json:"typeorder,omitempty"`
	FormatCommercialIfAny          string              `json:"Format_Commercial_IfAny,omitempty"`
	FormatSettingsEndianness       string              `json:"Format_Settings_Endianness,omitempty"`
	FormatAdditionalFeatures       string              `json:"Format_AdditionalFeatures,omitempty"`
	BitRateMode                    string              `json:"BitRate_Mode,omitempty"`
	Channels                       string              `json:"Channels,omitempty"`
	ChannelPositions               string              `json:"ChannelPositions,omitempty"`
	ChannelLayout                  string              `json:"ChannelLayout,omitempty"`
	SamplesPerFrame                string              `json:"SamplesPerFrame,omitempty"`
	SamplingRate                   string              `json:"SamplingRate,omitempty"`
	SamplingCount                  string              `json:"SamplingCount,omitempty"`
	CompressionMode                string              `json:"Compression_Mode,omitempty"`
	DelaySource                    string              `json:"Delay_Source,omitempty"`
	StreamSizeProportion           string              `json:"StreamSize_Proportion,omitempty"`
	Language                       string              `json:"Language,omitempty"`
	ServiceKind                    string              `json:"ServiceKind,omitempty"`
	Extra                          MediaInfoTrackExtra `json:"extra"`
	ElementCount                   string              `json:"ElementCount,omitempty"`
	Title                          string              `json:"Title,omitempty"`
}

type MediaInfoTrackExtra

type MediaInfoTrackExtra struct {
	Attachments             string `json:"Attachments,omitempty"`
	ComplexityIndex         string `json:"ComplexityIndex"`
	NumberOfDynamicObjects  string `json:"NumberOfDynamicObjects"`
	BedChannelCount         string `json:"BedChannelCount"`
	BedChannelConfiguration string `json:"BedChannelConfiguration"`
	Bsid                    string `json:"bsid"`
	Dialnorm                string `json:"dialnorm"`
	Compr                   string `json:"compr"`
	Acmod                   string `json:"acmod"`
	Lfeon                   string `json:"lfeon"`
	DialnormAverage         string `json:"dialnorm_Average"`
	DialnormMinimum         string `json:"dialnorm_Minimum"`
	ComprAverage            string `json:"compr_Average"`
	ComprMinimum            string `json:"compr_Minimum"`
	ComprMaximum            string `json:"compr_Maximum"`
	ComprCount              string `json:"compr_Count"`
}

type MediaInfoType

type MediaInfoType string

MediaInfoType defines a string type used to specify the category of media information metadata.

const (
	// General represents the media information type for general metadata.
	General MediaInfoType = "General"

	// Video represents the media information type for video-specific metadata.
	Video MediaInfoType = "Video"

	// Audio represents the media information type for audio-specific metadata.
	Audio MediaInfoType = "Audio"

	// Text represents the media information type for text-based metadata (subtitles).
	Text MediaInfoType = "Text"

	// Menu represents the media information type for menu-specific metadata (chapters).
	Menu MediaInfoType = "Menu"
)

type NFOFile

type NFOFile struct {
	Name    string
	Content []byte
}

NFOFile contains a single nfo file with content and filename.

func ParseNfoAttachment

func ParseNfoAttachment(path string) (NFOFile, error)

type NFOHandler

type NFOHandler struct {
	mkvparse.DefaultHandler

	Data        []byte
	FileName    string
	MIMEType    string
	Description string
	// contains filtered or unexported fields
}

func (*NFOHandler) HandleBinary

func (p *NFOHandler) HandleBinary(id mkvparse.ElementID, value []byte, info mkvparse.ElementInfo) error

func (*NFOHandler) HandleMasterEnd

func (p *NFOHandler) HandleMasterEnd(id mkvparse.ElementID, info mkvparse.ElementInfo) error

func (*NFOHandler) HandleString

func (p *NFOHandler) HandleString(id mkvparse.ElementID, value string, info mkvparse.ElementInfo) error

type ParallelFileRead

type ParallelFileRead int

ParallelFileRead is a type that defines if the files should be read in parallel.

const (
	// ParallelFileReadDisabled disables parallel file reading (better for hdds).
	ParallelFileReadDisabled ParallelFileRead = iota
	// ParallelFileReadEnabled enables parallel reading of files (improves performance on ssds).
	ParallelFileReadEnabled
	// ParallelFileReadAuto enables it if system is linux and ssd is detected.
	ParallelFileReadAuto
)

type Pre

type Pre struct {
	Name    string    `json:"name"`
	Group   string    `json:"group"`
	Section string    `json:"section"`
	Genre   string    `json:"genre"`
	Size    int64     `json:"size"`
	Files   int       `json:"files"`
	Nuke    string    `json:"nuke"`
	Time    time.Time `json:"pre_time"`
	Site    string    `json:"site"`
}

Pre is the struct that holds the pre-information.

type Resolution

type Resolution string

Resolution represents the video resolution quality

const (
	SD  Resolution = "sd"
	HD  Resolution = "720p"
	FHD Resolution = "1080p"
	UHD Resolution = "2160p"
)

func ParseResolution

func ParseResolution(name string) Resolution

ParseResolution determines the video resolution from the release name

type Section

type Section string

Section represents the category of a release

const (
	AppsMisc    Section = "apps-misc"
	AppsMacOS   Section = "apps-macos"
	AppsLinux   Section = "apps-linux"
	AppsWindows Section = "apps-windows"
)

Application categories

const (
	GamesWindows     Section = "games-windows"
	GamesMacOS       Section = "games-macos"
	GamesLinux       Section = "games-linux"
	GamesPlaystation Section = "games-playstation"
	GamesNintendo    Section = "games-nintendo"
	GamesXbox        Section = "games-xbox"
)

Game categories

const (
	AudioBooks Section = "abooks"
	AudioFLAC  Section = "flac"
	AudioMP3   Section = "mp3"
	AudioVideo Section = "mvid"
)

Audio categories

const (
	Movies Section = "movies"
	TV     Section = "tv"
	TVPack Section = "tv-pack"
	Sport  Section = "sport"
)

Video categories

const (
	XXX          Section = "xxx"
	XXXImagesets Section = "xxx-imagesets"
	XXXClips     Section = "xxx-clips"
	XXXDVD       Section = "xxx-dvd"
	XXXPack      Section = "xxx-pack"
	XXXMovies    Section = "xxx-movies"
)

Adult content categories

const (
	Tutorials Section = "tutorials"
	Mobile    Section = "mobile"
	Ebooks    Section = "ebooks"
	Unknown   Section = "unknown"
)

Miscellaneous categories

type Service

type Service struct {
	// contains filtered or unexported fields
}

func (*Service) CheckSFV

func (s *Service) CheckSFV(rel *Info, showProgress bool) error

CheckSFV verifies the integrity of files against SFV checksums and logs the results. It processes all ".sfv" files associated with the provided Info object.

func (*Service) CheckSRR

func (s *Service) CheckSRR(rel *Info, showProgress bool, fastCheck bool) error

CheckSRR validates the SRR integrity of a release using provided information and options.

func (*Service) CheckZip

func (s *Service) CheckZip(rel *Info, extractNFO bool) error

func (*Service) GetPre

func (s *Service) GetPre(name string) *Pre

GetPre searches for a pre on all available sources It ignores errors and returns nil if no pre was found.

func (*Service) Parse

func (s *Service) Parse(root string, ignore ...string) (*Info, error)

Parse processes a directory structure, extracts information, and builds a tree representation of its contents.

func (*Service) ParseSection

func (s *Service) ParseSection(name string, preInfo *Pre) Section

ParseSection tries to determine the section for the given release name

type ServiceBuilder

type ServiceBuilder struct {
	// contains filtered or unexported fields
}

ServiceBuilder is a builder for the Service.

func NewServiceBuilder

func NewServiceBuilder() *ServiceBuilder

NewServiceBuilder creates a new ServiceBuilder.

func (*ServiceBuilder) Build

func (s *ServiceBuilder) Build() *Service

Build creates a new Service from the builder.

func (*ServiceBuilder) WithHashThreads

func (s *ServiceBuilder) WithHashThreads(i int) *ServiceBuilder

WithHashThreads sets the number of threads to use for CRC32 checking.

func (*ServiceBuilder) WithParallelFileRead

func (s *ServiceBuilder) WithParallelFileRead(i int) *ServiceBuilder

WithParallelFileRead sets the parallelFileRead flag to enable or disable parallel file read mode. In this package it is used for the CRC32 calculation.

func (*ServiceBuilder) WithPreInfo

func (s *ServiceBuilder) WithPreInfo(preInfo *Pre) *ServiceBuilder

WithPreInfo sets the preInfo in advance and skips the pre-search.

func (*ServiceBuilder) WithSkipMediaInfo

func (s *ServiceBuilder) WithSkipMediaInfo(skip bool) *ServiceBuilder

WithSkipMediaInfo sets the skipMediaInfo flag to enable or disable mediainfo generation.

func (*ServiceBuilder) WithSkipPre

func (s *ServiceBuilder) WithSkipPre(skip bool) *ServiceBuilder

WithSkipPre sets the skipPre flag to enable or disable searching for pre-information.

func (*ServiceBuilder) WithSportPatterns

func (s *ServiceBuilder) WithSportPatterns(patterns []string) *ServiceBuilder

WithSportPatterns sets the sport patterns.

Directories

Path Synopsis
pkg

Jump to

Keyboard shortcuts

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