Documentation
¶
Overview ¶
Package blocklist manages the release blocklist used to skip known-bad releases.
⚠ Before changing anything in this file, run:
go test ./internal/core/blocklist/...
The tests (service_test.go) pin the stall-watcher's write path: AddFromStall, two-keyed dedup (guid OR info_hash), idempotency on duplicate insert, RemoveByGUID for the grab override flow, and the CountRecentStalls query used by the circuit breaker. Breaking any of these silently breaks automated dead-torrent blocklisting.
See pilot/CLAUDE.md "Regression guard: dead-torrent release search" for the full context.
Index ¶
- Constants
- Variables
- type Entry
- type Service
- func (s *Service) Add(ctx context.Context, ...) error
- func (s *Service) AddFromStall(ctx context.Context, p StallEntry) error
- func (s *Service) Clear(ctx context.Context) error
- func (s *Service) CountRecentStalls(ctx context.Context, seriesID, episodeID string) (int64, error)
- func (s *Service) Delete(ctx context.Context, id string) error
- func (s *Service) IsBlocklisted(ctx context.Context, releaseGUID string) (bool, error)
- func (s *Service) IsBlocklistedByTitle(ctx context.Context, releaseTitle string) (bool, error)
- func (s *Service) IsBlocklistedGUIDOrInfoHash(ctx context.Context, releaseGUID, infoHash string) (bool, error)
- func (s *Service) List(ctx context.Context, page, perPage int) ([]Entry, int64, error)
- func (s *Service) RemoveByGUID(ctx context.Context, releaseGUID string) error
- type StallEntry
Constants ¶
const ( ReasonUserMarked = "user_marked" ReasonStallNoPeersEver = "stall_no_peers_ever" ReasonStallActivityLost = "stall_activity_lost" )
Reason classifies why an entry is on the blocklist. The stall watcher uses stall_* reasons, users marking via UI use UserMarked. New reasons that start with "stall_" count toward the circuit breaker.
Variables ¶
var ErrAlreadyBlocklisted = errors.New("release already blocklisted")
ErrAlreadyBlocklisted is returned when adding a GUID that is already on the blocklist.
Functions ¶
This section is empty.
Types ¶
type Entry ¶
type Entry struct {
ID string
SeriesID string
SeriesTitle string
EpisodeID string
ReleaseGUID string
ReleaseTitle string
IndexerID string
Protocol string
Size int64
AddedAt time.Time
Notes string
Reason string
InfoHash string
}
Entry is the domain representation of a blocklist record.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service manages the release blocklist.
func (*Service) Add ¶
func (s *Service) Add(ctx context.Context, seriesID, episodeID, releaseGUID, releaseTitle, indexerID, protocol string, size int64, notes string) error
Add inserts a new user-marked blocklist entry. Returns ErrAlreadyBlocklisted if the GUID is already present (the unique index on release_guid enforces this). For automated stall-detected entries, use AddFromStall instead so the reason field is set correctly.
func (*Service) AddFromStall ¶
func (s *Service) AddFromStall(ctx context.Context, p StallEntry) error
AddFromStall inserts a blocklist entry triggered by Haul's stall detection. reason must be one of the stall_* constants; info_hash may be empty if unavailable. Idempotent — double-fires are swallowed via ErrAlreadyBlocklisted (callers usually treat that as success).
func (*Service) CountRecentStalls ¶
CountRecentStalls counts stall-reason blocklist entries for a given (series, episode) within the last 24 hours. Used by the auto-re-search circuit breaker to stop after a configurable number of stall retries.
func (*Service) IsBlocklisted ¶
IsBlocklisted reports whether a release GUID is on the blocklist.
func (*Service) IsBlocklistedByTitle ¶
IsBlocklistedByTitle reports whether a release title is on the blocklist.
func (*Service) IsBlocklistedGUIDOrInfoHash ¶
func (s *Service) IsBlocklistedGUIDOrInfoHash(ctx context.Context, releaseGUID, infoHash string) (bool, error)
IsBlocklistedGUIDOrInfoHash reports whether a release is on the blocklist under either its original GUID or its info hash. This is the two-keyed dedup the search filter uses so a release re-surfaced from a different indexer (different GUID, same content) still gets filtered.
func (*Service) RemoveByGUID ¶
RemoveByGUID removes a blocklist entry by its release GUID. Used by the grab-override flow so a user can force-grab a previously-blocklisted release and have it disappear from the blocklist in one click.