Documentation
¶
Overview ¶
Package dirscan provides directory scanning functionality to find media files and match them against Torznab indexers for cross-seeding.
Index ¶
- Constants
- func CalculateSizeRange(searcheeSize int64, tolerancePercent float64) (minSize, maxSize int64)
- func CalculateTotalSize(searchee *Searchee) int64
- func ParseSeasonFolder(name string) (season int, ok bool)
- type Config
- type InjectRequest
- type InjectResult
- type Injector
- func (i *Injector) Inject(ctx context.Context, req *InjectRequest) (*InjectResult, error)
- func (i *Injector) InjectBatch(ctx context.Context, requests []*InjectRequest) []*InjectResult
- func (i *Injector) TorrentExists(ctx context.Context, instanceID int, hash string) (bool, error)
- func (i *Injector) TorrentExistsAny(ctx context.Context, instanceID int, hashes []string) (bool, error)
- type InstanceProvider
- type JackettDownloader
- type JackettSearcher
- type MatchMode
- type MatchResult
- type MatchedFilePair
- type Matcher
- type ParsedTorrent
- type Parser
- type ScanResult
- type ScannedFile
- type Scanner
- type SearchRequest
- type SearchResult
- type Searchee
- type SearcheeMetadata
- type Searcher
- type Service
- func (s *Service) CancelScan(ctx context.Context, directoryID int) error
- func (s *Service) CreateDirectory(ctx context.Context, dir *models.DirScanDirectory) (*models.DirScanDirectory, error)
- func (s *Service) DeleteDirectory(ctx context.Context, id int) error
- func (s *Service) GetActiveRun(ctx context.Context, directoryID int) (*models.DirScanRun, error)
- func (s *Service) GetDirectory(ctx context.Context, id int) (*models.DirScanDirectory, error)
- func (s *Service) GetSettings(ctx context.Context) (*models.DirScanSettings, error)
- func (s *Service) GetStatus(ctx context.Context, directoryID int) (*models.DirScanRun, error)
- func (s *Service) ListDirectories(ctx context.Context) ([]*models.DirScanDirectory, error)
- func (s *Service) ListFiles(ctx context.Context, directoryID int, status *models.DirScanFileStatus, ...) ([]*models.DirScanFile, error)
- func (s *Service) ListRunInjections(ctx context.Context, directoryID int, runID int64, limit, offset int) ([]*models.DirScanRunInjection, error)
- func (s *Service) ListRuns(ctx context.Context, directoryID, limit int) ([]*models.DirScanRun, error)
- func (s *Service) ResetFilesForDirectory(ctx context.Context, directoryID int) error
- func (s *Service) Start(ctx context.Context) error
- func (s *Service) StartManualScan(ctx context.Context, directoryID int) (int64, error)
- func (s *Service) Stop()
- func (s *Service) UpdateDirectory(ctx context.Context, id int, params *models.DirScanDirectoryUpdateParams) (*models.DirScanDirectory, error)
- func (s *Service) UpdateSettings(ctx context.Context, settings *models.DirScanSettings) (*models.DirScanSettings, error)
- type TRaSHMetadata
- type TorrentAdder
- type TorrentChecker
- type TorrentFile
Constants ¶
const SearchScope = "dir-scan"
SearchScope is the cache scope used for dir-scan searches.
Variables ¶
This section is empty.
Functions ¶
func CalculateSizeRange ¶
CalculateSizeRange calculates min/max size based on searchee size and tolerance.
func CalculateTotalSize ¶
CalculateTotalSize calculates the total size of a searchee.
func ParseSeasonFolder ¶
ParseSeasonFolder attempts to parse a folder name as a season folder. Returns the season number (0 for Specials) and true if it matches, or 0 and false if not.
Types ¶
type Config ¶
type Config struct {
// SchedulerInterval is how often to check for scheduled scans.
SchedulerInterval time.Duration
// MaxJitter is the maximum random delay before starting a scheduled scan.
MaxJitter time.Duration
// MaxConcurrentRuns limits how many scans can run across all directories.
// This helps avoid stampeding indexers if multiple directories are due at once.
MaxConcurrentRuns int
}
Config holds configuration for the directory scanner service.
type InjectRequest ¶
type InjectRequest struct {
// InstanceID is the target qBittorrent instance.
InstanceID int
// TorrentBytes contains the .torrent file contents.
TorrentBytes []byte
// ParsedTorrent is the parsed torrent metadata for TorrentBytes.
ParsedTorrent *ParsedTorrent
// Searchee that was matched.
Searchee *Searchee
// MatchResult is the file-level match for this searchee and ParsedTorrent.
MatchResult *MatchResult
// SearchResult that matched the searchee.
SearchResult *jackett.SearchResult
// SavePath is the path where qBittorrent should save the torrent.
// This should point to the parent directory of the searchee.
SavePath string
// QbitPathPrefix is an optional path prefix to apply for container path mapping.
// If set, replaces the searchee's path prefix for qBittorrent injection.
QbitPathPrefix string
// Category to assign to the torrent.
Category string
// Tags to assign to the torrent.
Tags []string
// StartPaused adds the torrent in paused state.
StartPaused bool
}
InjectRequest contains parameters for injecting a torrent.
type InjectResult ¶
type InjectResult struct {
// Success is true if the torrent was added successfully.
Success bool
// TorrentHash is the hash of the added torrent.
TorrentHash string
// Mode describes how the torrent was added: hardlink, reflink, or regular.
Mode string
// SavePath is the save path used when adding the torrent.
SavePath string
// Error message if injection failed.
ErrorMessage string
}
InjectResult contains the result of an injection attempt.
type Injector ¶
type Injector struct {
// contains filtered or unexported fields
}
Injector handles downloading and injecting torrents into qBittorrent.
func NewInjector ¶
func NewInjector( jackettService JackettDownloader, syncManager TorrentAdder, torrentChecker TorrentChecker, instanceStore InstanceProvider, trackerCustomizationStore trackerCustomizationProvider, ) *Injector
NewInjector creates a new injector.
func (*Injector) Inject ¶
func (i *Injector) Inject(ctx context.Context, req *InjectRequest) (*InjectResult, error)
Inject downloads a torrent and injects it into qBittorrent.
func (*Injector) InjectBatch ¶
func (i *Injector) InjectBatch(ctx context.Context, requests []*InjectRequest) []*InjectResult
InjectBatch injects multiple torrents. Returns results for each injection attempt.
func (*Injector) TorrentExists ¶
TorrentExists checks if a torrent with the given hash already exists in qBittorrent.
type InstanceProvider ¶
type JackettDownloader ¶
type JackettDownloader interface {
DownloadTorrent(ctx context.Context, req jackett.TorrentDownloadRequest) ([]byte, error)
}
JackettDownloader is the interface for downloading torrent files.
type JackettSearcher ¶
type JackettSearcher interface {
SearchWithScope(ctx context.Context, req *jackett.TorznabSearchRequest, scope string) error
}
JackettSearcher is the interface for the jackett service search functionality.
type MatchResult ¶
type MatchResult struct {
// IsMatch is true if the match criteria were met
IsMatch bool
// MatchedFiles contains the matched file pairs
MatchedFiles []MatchedFilePair
// UnmatchedSearcheeFiles contains searchee files that weren't matched
UnmatchedSearcheeFiles []*ScannedFile
// UnmatchedTorrentFiles contains torrent files that weren't matched
UnmatchedTorrentFiles []TorrentFile
// MatchRatio is the ratio of matched files (0.0-1.0)
MatchRatio float64
// SizeMatchRatio is the ratio of matched size (0.0-1.0)
SizeMatchRatio float64
// IsPerfectMatch is true if all files matched
IsPerfectMatch bool
// IsPartialMatch is true if some but not all files matched
IsPartialMatch bool
}
MatchResult represents the result of matching a searchee against a torrent.
type MatchedFilePair ¶
type MatchedFilePair struct {
SearcheeFile *ScannedFile
TorrentFile TorrentFile
}
MatchedFilePair represents a matched pair of searchee file and torrent file.
type Matcher ¶
type Matcher struct {
// contains filtered or unexported fields
}
Matcher handles matching searchees against torrent file lists.
func NewMatcher ¶
NewMatcher creates a new matcher.
func (*Matcher) Match ¶
func (m *Matcher) Match(searchee *Searchee, torrentFiles []TorrentFile) *MatchResult
Match attempts to match a searchee's files against a torrent's files.
type ParsedTorrent ¶
type ParsedTorrent struct {
Name string
InfoHash string
Files []TorrentFile
TotalSize int64
PieceLength int64
PieceCount int
}
ParsedTorrent holds parsed torrent metadata.
func ParseTorrentBytes ¶
func ParseTorrentBytes(data []byte) (*ParsedTorrent, error)
ParseTorrentBytes parses a .torrent file and extracts file information.
type Parser ¶
type Parser struct {
// contains filtered or unexported fields
}
Parser handles name parsing with TRaSH ID extraction and rls integration.
func (*Parser) Parse ¶
func (p *Parser) Parse(name string) *SearcheeMetadata
Parse extracts TRaSH IDs and parses release metadata from a searchee name.
type ScanResult ¶
type ScanResult struct {
Searchees []*Searchee // Searchees found
TotalFiles int // Total media files found
TotalSize int64 // Total size in bytes
SkippedFiles int // Files skipped (already seeding, etc.)
}
ScanResult holds the results of a directory scan.
type ScannedFile ¶
type ScannedFile struct {
Path string // Absolute path to the file
RelPath string // Relative path from searchee root
Size int64 // File size in bytes
ModTime time.Time // Modification time
FileID hardlink.FileID // Platform-specific file identifier
LinkCount uint64 // Hardlink count
HasLinks bool // True if file has multiple hardlinks (count > 1)
}
ScannedFile represents a file found during directory scanning.
type Scanner ¶
type Scanner struct {
// contains filtered or unexported fields
}
Scanner walks directories and collects media files into searchees.
func (*Scanner) CheckAlreadySeeding ¶
CheckAlreadySeeding checks if a searchee's files are already being seeded.
func (*Scanner) ScanDirectory ¶
ScanDirectory walks a directory and returns searchees.
func (*Scanner) SetFileIDIndex ¶
SetFileIDIndex sets the FileID index for detecting already-seeding files.
type SearchRequest ¶
type SearchRequest struct {
// Searchee to search for
Searchee *Searchee
// Metadata parsed from the searchee name (optional, will be parsed if nil)
Metadata *SearcheeMetadata
// IndexerIDs to search (empty = all enabled indexers)
IndexerIDs []int
// Categories to search (optional, but recommended for better results).
Categories []int
// Limit results per indexer
Limit int
// OnAllComplete is called when all search jobs complete with the final results
OnAllComplete func(response *jackett.SearchResponse, err error)
}
SearchRequest contains parameters for searching a searchee.
type SearchResult ¶
type SearchResult struct {
*jackett.SearchResult
// IndexerID that returned this result
IndexerID int
// Searchee this result is for
Searchee *Searchee
// MatchScore indicates match quality (higher is better)
MatchScore float64
}
SearchResult wraps a jackett search result with additional matching context.
func FilterResults ¶
func FilterResults(results []*SearchResult, minSize, maxSize int64) []*SearchResult
FilterResults filters search results based on basic criteria.
type Searchee ¶
type Searchee struct {
Name string // Release name (folder or file base name)
Path string // Absolute path to the searchee root
Files []*ScannedFile // Files in this searchee
IsDisc bool // True if this is a disc-layout folder
}
Searchee represents a unit to search for on indexers (folder or single file).
type SearcheeMetadata ¶
type SearcheeMetadata struct {
// Original name before any processing
OriginalName string
// CleanedName has TRaSH IDs removed (suitable for rls parsing)
CleanedName string
// TRaSH IDs extracted from the name
TRaSH TRaSHMetadata
// Release metadata from rls parsing
Release *rls.Release
// Derived search fields
Title string // Cleaned title for search queries
Year int // Year if detected
Season *int // Season number for TV
Episode *int // Episode number for TV
// Content type hints
IsTV bool
IsMovie bool
IsMusic bool
}
SearcheeMetadata combines TRaSH IDs with rls parsed release metadata.
func (*SearcheeMetadata) GetIMDbID ¶
func (m *SearcheeMetadata) GetIMDbID() string
GetIMDbID returns the IMDb ID in a format suitable for Torznab search. Returns empty string if not available.
func (*SearcheeMetadata) GetTMDbID ¶
func (m *SearcheeMetadata) GetTMDbID() int
GetTMDbID returns the TMDb ID if available, 0 otherwise.
func (*SearcheeMetadata) GetTVDbID ¶
func (m *SearcheeMetadata) GetTVDbID() int
GetTVDbID returns the TVDb ID if available, 0 otherwise.
func (*SearcheeMetadata) HasExternalIDs ¶
func (m *SearcheeMetadata) HasExternalIDs() bool
HasExternalIDs returns true if any external database IDs are available.
func (*SearcheeMetadata) SetExternalIDs ¶
func (m *SearcheeMetadata) SetExternalIDs(imdbID string, tmdbID, tvdbID int)
SetExternalIDs updates the metadata with external IDs from arr lookup. Only sets IDs that are not already present from TRaSH naming.
type Searcher ¶
type Searcher struct {
// contains filtered or unexported fields
}
Searcher handles searching Torznab indexers for matching torrents.
func NewSearcher ¶
func NewSearcher(jackettService JackettSearcher, parser *Parser) *Searcher
NewSearcher creates a new searcher.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service handles directory scanning and torrent matching.
func NewService ¶
func NewService( cfg Config, store *models.DirScanStore, instanceStore *models.InstanceStore, syncManager *qbittorrent.SyncManager, jackettService *jackett.Service, arrService *arr.Service, trackerCustomizationStore *models.TrackerCustomizationStore, ) *Service
NewService creates a new directory scanner service.
func (*Service) CancelScan ¶
CancelScan cancels an active scan.
func (*Service) CreateDirectory ¶
func (s *Service) CreateDirectory(ctx context.Context, dir *models.DirScanDirectory) (*models.DirScanDirectory, error)
CreateDirectory creates a new scan directory.
func (*Service) DeleteDirectory ¶
DeleteDirectory deletes a scan directory.
func (*Service) GetActiveRun ¶
GetActiveRun returns the currently active run for a directory, if any.
func (*Service) GetDirectory ¶
GetDirectory returns a scan directory by ID.
func (*Service) GetSettings ¶
GetSettings returns the global directory scanner settings.
func (*Service) GetStatus ¶
GetStatus returns the status of a directory's current or most recent scan.
func (*Service) ListDirectories ¶
ListDirectories returns all configured scan directories.
func (*Service) ListFiles ¶
func (s *Service) ListFiles(ctx context.Context, directoryID int, status *models.DirScanFileStatus, limit, offset int) ([]*models.DirScanFile, error)
ListFiles returns scanned files for a directory.
func (*Service) ListRunInjections ¶
func (s *Service) ListRunInjections(ctx context.Context, directoryID int, runID int64, limit, offset int) ([]*models.DirScanRunInjection, error)
ListRunInjections returns injection attempts (added/failed) for a run.
func (*Service) ListRuns ¶
func (s *Service) ListRuns(ctx context.Context, directoryID, limit int) ([]*models.DirScanRun, error)
ListRuns returns recent scan runs for a directory.
func (*Service) ResetFilesForDirectory ¶
ResetFilesForDirectory deletes all tracked scan progress files for a directory.
func (*Service) StartManualScan ¶
StartManualScan starts a manual scan for a directory.
func (*Service) UpdateDirectory ¶
func (s *Service) UpdateDirectory(ctx context.Context, id int, params *models.DirScanDirectoryUpdateParams) (*models.DirScanDirectory, error)
UpdateDirectory updates a scan directory.
func (*Service) UpdateSettings ¶
func (s *Service) UpdateSettings(ctx context.Context, settings *models.DirScanSettings) (*models.DirScanSettings, error)
UpdateSettings updates the global directory scanner settings.
type TRaSHMetadata ¶
type TRaSHMetadata struct {
TMDbID int // From {tmdb-345691}
IMDbID string // From {imdb-tt1234567}
TVDbID int // From [tvdb-123] or [tvdbid-123]
Edition string // From {edition-Extended}
}
TRaSHMetadata holds database IDs extracted from TRaSH Guides naming conventions. See: https://trash-guides.info/
type TorrentAdder ¶
type TorrentAdder interface {
AddTorrent(ctx context.Context, instanceID int, fileContent []byte, options map[string]string) error
BulkAction(ctx context.Context, instanceID int, hashes []string, action string) error
ResumeWhenComplete(instanceID int, hashes []string, opts qbsync.ResumeWhenCompleteOptions)
}
TorrentAdder is the interface for adding torrents to qBittorrent.
type TorrentChecker ¶
type TorrentChecker interface {
HasTorrentByAnyHash(ctx context.Context, instanceID int, hashes []string) (*qbt.Torrent, bool, error)
}
TorrentChecker is the interface for checking if torrents exist in qBittorrent.
type TorrentFile ¶
type TorrentFile struct {
Path string // Relative path within the torrent
Size int64 // Size in bytes
Offset int64 // Byte offset in the torrent's byte stream (for piece calculation)
}
TorrentFile represents a file within a torrent.