mdblist

package
v0.3.9 Latest Latest
Warning

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

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

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrBusy = errors.New("mdblist: account is busy")
View Source
var ErrUnsupported = errors.New("mdblist: history identity unsupported")

ErrUnsupported marks a history identity MDBList cannot resolve or store.

Functions

func Enqueue

func Enqueue(ctx context.Context, db *sql.DB, ev state.Event) error

Enqueue records local completions only for linked viewers. Imports do not echo back to their source, and an unwatch never deletes remote history.

func Handler

func Handler(d HandlerDeps) http.Handler

func HistoryPayload

func HistoryPayload(key core.RatingKey, at time.Time) (map[string]any, error)

HistoryPayload uses only identities represented unambiguously by Ether's native movie and episode keys. Show and season keys are skipped. Episodes are sent in TMDb numbering (nested, by season/episode number), which is what MDBList's sync documents as the canonical form. https://api.mdblist.com/docs/ (POST /sync/watched)

func ParseHistory

func ParseHistory(user int64, data []byte) ([]state.ImportRecord, int, error)

ParseHistory accepts only actual timestamps and TMDB identities. Movies are read from `movies[]`; watched episodes from the flat `episodes[]`, which carry the parent show's TMDb id and TMDb season/episode numbers, exactly the grain Ether stores. Shows and seasons are skipped: their watched state is already implied by their episodes. https://api.mdblist.com/docs/ (GET /sync/watched)

func RunDelivery

func RunDelivery(ctx context.Context, service func() Service, enabled func() bool, log *slog.Logger)

RunDelivery is a leader-only loop. State events are enqueued by every node, but a shared per-viewer lease fences concurrent manual sync and delivery.

Types

type Client

type Client struct {
	BaseURL string
	HTTP    *http.Client
}

Client talks to MDBList's account API using a viewer's personal API key. The key travels as MDBList's documented `apikey` query parameter.

func (Client) PullHistory

func (c Client) PullHistory(ctx context.Context, user int64, apiKey, cursor string) ([]state.ImportRecord, string, int, error)

PullHistory reads the watched snapshot with cursor pagination. Movies and episodes are returned by default; the returned cursor must only be saved after all imported records commit. A first pull (empty cursor) reads from the beginning; later pulls pass the cursor to continue. https://api.mdblist.com/docs/ (GET /sync/watched)

func (Client) PushHistory

func (c Client) PushHistory(ctx context.Context, apiKey string, key core.RatingKey, at time.Time) error

PushHistory sends one completion. MDBList records a play per request and treats a re-sent already-watched item without a date as a no-op, so a retry after an uncertain response is idempotent. A 4xx that means the item cannot be written is reported as ErrUnsupported so the caller can drop it.

type Grant

type Grant struct {
	APIKey string
}

Grant is one viewer's MDBList credential together with its lease state.

type HTTPError

type HTTPError struct {
	Status     int
	RetryAfter string
}

HTTPError exposes status and Retry-After without copying upstream bodies into logs. Callers must honour Retry-After before retrying a rate limit.

func (*HTTPError) Error

func (e *HTTPError) Error() string

type HandlerDeps

type HandlerDeps struct {
	Tokens  *TokenStore
	Service func() Service
	Viewer  func(context.Context, int64) bool
	Enabled func() bool
}

HandlerDeps are explicitly provided by the owner-authenticated admin API. Viewer validates that an ID identifies a current viewer, never a caller- supplied arbitrary account. Authentication is enforced by the mounting API.

type Service

type Service struct {
	Client Client
	Tokens TokenStore
	State  *state.State
}

Service is supplied explicit state and credential dependencies. Manual sync uses a lease and a deadline shorter than the lease; it never advances the snapshot after a partial pull.

func (Service) FlushOne

func (s Service) FlushOne(ctx context.Context, user int64) error

FlushOne delivers at most one queued event under the per-viewer lease. The caller runs it only on the cluster leader. MDBList's watched write is idempotent for already-watched items, including retries after an uncertain response, so a re-sent completion cannot create a duplicate play.

func (Service) Sync

func (s Service) Sync(ctx context.Context, user int64) (SyncResult, error)

Sync imports a viewer's MDBList watch history. It is intended as a one-time (or occasional) backfill; ongoing sync is export-only, since MDBList's watched endpoint is a snapshot rather than a per-item change feed.

type SyncResult

type SyncResult struct {
	Imported int `json:"imported"`
	Skipped  int `json:"skipped"`
}

type TokenStore

type TokenStore struct {
	DB     *sql.DB
	Sealer config.FieldSealer
}

TokenStore keeps one API key per viewer, sealed and bound to its row. A working field sealer is mandatory: keys are never stored in cleartext, including during the legacy credential upgrade.

func (TokenStore) AcquireLease

func (s TokenStore) AcquireLease(ctx context.Context, user int64, now time.Time) (string, error)

AcquireLease reserves a viewer account across nodes for bounded remote work. Operations must end before the deadline; every update also checks the lease id, since a paused process may wake after losing its reservation.

func (TokenStore) Delete

func (s TokenStore) Delete(ctx context.Context, user int64) error

Delete removes a viewer's key and queue under the viewer lock. It is a no-op when nothing is stored, and refuses while a lease is held.

func (TokenStore) Load

func (s TokenStore) Load(ctx context.Context, user int64) (Grant, error)

Load returns the viewer's key. A row that carries no longer opens (wrong key or moved to another viewer) is an error, never a silent empty key.

func (TokenStore) Pop

func (s TokenStore) Pop(ctx context.Context, user int64) (Grant, error)

Pop removes a viewer's key and queue, returning the key only when it actually removed the row. Used by merge/lifecycle bookkeeping.

func (TokenStore) ReleaseLease

func (s TokenStore) ReleaseLease(ctx context.Context, user int64, id string) error

func (TokenStore) Save

func (s TokenStore) Save(ctx context.Context, user int64, key string, now time.Time) error

Save stores or replaces a viewer's API key. The key is bound to that viewer, so a value copied to another row fails to open.

Jump to

Keyboard shortcuts

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