blocklist

package
v0.0.0-...-d771ed5 Latest Latest
Warning

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

Go to latest
Published: May 29, 2026 License: MIT Imports: 7 Imported by: 0

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

View Source
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

View Source
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 NewService

func NewService(q db.Querier) *Service

NewService creates a new Service.

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) Clear

func (s *Service) Clear(ctx context.Context) error

Clear removes all blocklist entries.

func (*Service) CountRecentStalls

func (s *Service) CountRecentStalls(ctx context.Context, seriesID, episodeID string) (int64, error)

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) Delete

func (s *Service) Delete(ctx context.Context, id string) error

Delete removes a single blocklist entry by ID.

func (*Service) IsBlocklisted

func (s *Service) IsBlocklisted(ctx context.Context, releaseGUID string) (bool, error)

IsBlocklisted reports whether a release GUID is on the blocklist.

func (*Service) IsBlocklistedByTitle

func (s *Service) IsBlocklistedByTitle(ctx context.Context, releaseTitle string) (bool, error)

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) List

func (s *Service) List(ctx context.Context, page, perPage int) ([]Entry, int64, error)

List returns a paginated list of blocklist entries, newest first.

func (*Service) RemoveByGUID

func (s *Service) RemoveByGUID(ctx context.Context, releaseGUID string) error

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.

type StallEntry

type StallEntry struct {
	SeriesID     string
	EpisodeID    string
	ReleaseGUID  string
	ReleaseTitle string
	IndexerID    string
	Protocol     string
	Size         int64
	Notes        string
	Reason       string // must be a stall_* constant
	InfoHash     string
}

StallEntry is the shape of a stall-triggered blocklist insert.

Jump to

Keyboard shortcuts

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