douban

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jun 14, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Overview

Package douban is the library behind the douban command: the HTTP client, request shaping, and typed data models for Douban (豆瓣).

The client reads Douban through the public web surfaces that serve without a login: subject search, the j/subject_suggest JSON endpoints, book subject pages, the Top 250 / chart / now-playing film lists, and curated doulists. No API key or authentication is required. It sets a real User-Agent, paces requests, and retries transient 429/5xx errors with exponential backoff.

Douban's subdomains differ in anti-bot posture: book subject pages serve fully, but movie subject and celebrity pages redirect to a sec.douban.com challenge. Film data is therefore reached through suggest and the list pages rather than per-film detail pages.

Index

Constants

View Source
const (
	// DefaultFrodoBase is the Frodo API origin.
	DefaultFrodoBase = "https://frodo.douban.com"
	// DefaultFrodoKey and DefaultFrodoSecret are a recognized Frodo app key pair.
	// They can be overridden via FrodoConfig (or CLI flags) if Douban rotates them.
	DefaultFrodoKey    = "0dad551ec0f84ed02907ff5c42e8ec70"
	DefaultFrodoSecret = "bf7dddc7c9cfe6f7"
	// DefaultFrodoUA is the Frodo Android client User-Agent. The host rejects
	// any request whose UA does not identify the app (it answers
	// invalid_apikey, code 1062), so this string is not cosmetic. The
	// "api-client/1 " prefix matches the form the live app sends.
	DefaultFrodoUA = "" /* 144-byte string literal not displayed */
)
View Source
const DefaultUserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"

DefaultUserAgent is the browser-like User-Agent sent with every request.

Variables

View Source
var ErrForbidden = errors.New("douban: forbidden")

ErrForbidden is returned for a 403, which on Douban means a wall (login-gated or anti-bot) rather than a transient error. Callers record it as blocked so it is not retried like a recoverable failure.

View Source
var ErrNotFound = errors.New("douban: not found")

ErrNotFound is returned when Douban has no subject, list, or page for an id.

Functions

func Defaults added in v0.3.0

func Defaults(c *kit.Config)

Defaults seeds the framework baseline with douban's own values, so an unset --rate or --timeout uses the douban default rather than the generic kit one. It is passed to kit.New via kit.WithDefaults.

func Identity added in v0.3.0

func Identity() kit.Identity

Identity is the fixed description of the douban CLI, shared by the domain and the standalone composition root so help and version read the same everywhere.

Types

type Book added in v0.2.0

type Book struct {
	ID            string `json:"id"`
	Title         string `json:"title"`
	OriginalTitle string `json:"original_title,omitempty"`
	Author        string `json:"author,omitempty"`
	Translator    string `json:"translator,omitempty"`
	Publisher     string `json:"publisher,omitempty"`
	Producer      string `json:"producer,omitempty"`
	PubDate       string `json:"pubdate,omitempty"`
	Pages         string `json:"pages,omitempty"`
	Price         string `json:"price,omitempty"`
	Binding       string `json:"binding,omitempty"`
	Series        string `json:"series,omitempty"`
	ISBN          string `json:"isbn,omitempty"`
	Rating        string `json:"rating"`
	Summary       string `json:"summary,omitempty" table:",truncate"`
	URL           string `json:"url"`
	Cover         string `json:"cover,omitempty" table:",truncate"`
}

Book is the full record for one book subject.

type Client

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

Client talks to Douban's public web surfaces.

func ClientFromConfig added in v0.3.0

func ClientFromConfig(cfg kit.Config) *Client

ClientFromConfig maps the framework config onto a douban.Config and returns a client. The mirror commands reuse it so the CLI surface and the crawler share one notion of rate, timeout, retries, and User-Agent.

func NewClient

func NewClient(cfg Config) *Client

NewClient returns a Client configured with cfg.

func (*Client) Book added in v0.2.0

func (c *Client) Book(ctx context.Context, idOrURL string) (*Book, error)

Book fetches the full record for one book subject. The argument may be a bare id or a pasted book.douban.com URL.

func (*Client) Chart added in v0.2.0

func (c *Client) Chart(ctx context.Context) ([]Movie, error)

Chart returns the current Douban film ranking board (/chart).

func (*Client) Doulist added in v0.2.0

func (c *Client) Doulist(ctx context.Context, idOrURL string, limit int) ([]DoulistItem, error)

Doulist returns the subjects in a curated list (豆列) in list order. The argument may be a bare id or a pasted www.douban.com/doulist URL. It walks the paged ?start= listing until limit items are collected (default 100).

func (*Client) Get added in v0.2.0

func (c *Client) Get(ctx context.Context, rawURL string) ([]byte, error)

Get fetches a URL and returns the body, pacing and retrying as configured. It is the exported entry point used by the mirror crawler to fetch arbitrary Douban URLs (sitemaps, subject pages); the lookup commands use the typed helpers built on the same internal get.

func (*Client) NowPlaying added in v0.2.0

func (c *Client) NowPlaying(ctx context.Context, city string, coming bool, limit int) ([]Movie, error)

NowPlaying returns the films in cinemas now for a city (default beijing). When coming is true it returns the upcoming list from the same page instead.

func (*Client) Search

func (c *Client) Search(ctx context.Context, query, searchType string, limit int) ([]Result, error)

Search fetches Douban subject-search results for query and searchType. searchType must be one of "book", "movie", or "music". Up to limit results are returned; pass 0 to use a reasonable default (15).

func (*Client) Suggest added in v0.2.0

func (c *Client) Suggest(ctx context.Context, query, suggestType string, limit int) ([]Suggestion, error)

Suggest queries Douban's j/subject_suggest typeahead. suggestType selects the catalog ("movie" or "book"); movie is the reliable way to resolve a film id, since movie subject pages are sealed. Up to limit results are returned.

func (*Client) Top250 added in v0.2.0

func (c *Client) Top250(ctx context.Context, limit int) ([]Movie, error)

Top250 returns the Douban Top 250 films in rank order. It walks the paged ?start= listing until limit rows are collected (default and maximum 250).

type Config

type Config struct {
	// BaseURL overrides the host for tests. When empty the client talks to the
	// real https://<sub>.douban.com subdomains; when set, every host resolves to
	// this single base and is dispatched by path.
	BaseURL   string
	UserAgent string
	Rate      time.Duration
	Timeout   time.Duration
	Retries   int
}

Config holds constructor parameters.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns sensible defaults.

type Domain added in v0.3.0

type Domain struct{}

Domain is the douban driver for the any-cli/kit framework. It declares the lookup operations once, and kit derives the CLI subcommands, the HTTP API routes, and the MCP tools from that single registry. The same Domain powers the standalone douban binary and a multi-domain host that mounts it.

func (Domain) Info added in v0.3.0

func (Domain) Info() kit.DomainInfo

Info describes the domain: its URI scheme, the hosts it owns, and the identity the standalone binary reuses for help and version.

func (Domain) Register added in v0.3.0

func (Domain) Register(app *kit.App)

Register installs the client factory and every lookup operation on the app. The mirror subsystem is wired as escape-hatch commands by the cli package, since it is CLI-only (stateful crawl, not the emit-records shape).

type DoulistItem added in v0.2.0

type DoulistItem struct {
	Rank     int    `json:"rank"`
	ID       string `json:"id"`
	Title    string `json:"title"`
	Rating   string `json:"rating"`
	Abstract string `json:"abstract,omitempty" table:",truncate"`
	URL      string `json:"url"`
	Cover    string `json:"cover,omitempty" table:",truncate"`
}

DoulistItem is one subject in a curated list.

type FrodoClient added in v0.2.0

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

FrodoClient calls the signed Frodo API.

func NewFrodoClient added in v0.2.0

func NewFrodoClient(cfg FrodoConfig) *FrodoClient

NewFrodoClient returns a FrodoClient. Empty config fields fall back to the DefaultFrodoConfig values.

func (*FrodoClient) Book added in v0.2.0

func (f *FrodoClient) Book(ctx context.Context, id string) ([]byte, error)

func (*FrodoClient) Celebrities added in v0.2.0

func (f *FrodoClient) Celebrities(ctx context.Context, id string) ([]byte, error)

Celebrities returns the directors/actors credit list for a movie.

func (*FrodoClient) Game added in v0.2.0

func (f *FrodoClient) Game(ctx context.Context, id string) ([]byte, error)

func (*FrodoClient) Get added in v0.2.0

func (f *FrodoClient) Get(ctx context.Context, path string, params url.Values) ([]byte, error)

Get fetches a signed API path and returns the raw JSON body. It paces and retries transient failures; a 404 maps to ErrNotFound and an API error envelope to *FrodoError.

func (*FrodoClient) Interests added in v0.2.0

func (f *FrodoClient) Interests(ctx context.Context, typ, id string, start, count int) ([]byte, error)

Interests returns the public per-user ratings and short comments for a subject.

func (*FrodoClient) Movie added in v0.2.0

func (f *FrodoClient) Movie(ctx context.Context, id string) ([]byte, error)

Movie, Book, Music, Game fetch a subject detail of that type.

func (*FrodoClient) Music added in v0.2.0

func (f *FrodoClient) Music(ctx context.Context, id string) ([]byte, error)

func (*FrodoClient) Personage added in v0.2.0

func (f *FrodoClient) Personage(ctx context.Context, id string) ([]byte, error)

Personage fetches the rich celebrity/personage profile (elessar subject).

func (*FrodoClient) Photos added in v0.2.0

func (f *FrodoClient) Photos(ctx context.Context, typ, id string, start, count int) ([]byte, error)

Photos returns the photo gallery for a subject.

func (*FrodoClient) Rating added in v0.2.0

func (f *FrodoClient) Rating(ctx context.Context, typ, id string) ([]byte, error)

Rating returns the rating breakdown (star distribution, wish/doing/done) for a subject.

func (*FrodoClient) Reviews added in v0.2.0

func (f *FrodoClient) Reviews(ctx context.Context, typ, id string, start, count int) ([]byte, error)

Reviews returns the long reviews for a subject.

func (*FrodoClient) SearchSubjects added in v0.2.0

func (f *FrodoClient) SearchSubjects(ctx context.Context, q string, start, count int) ([]byte, error)

SearchSubjects searches across subjects; filter results by item.target_type.

func (*FrodoClient) Subject added in v0.2.0

func (f *FrodoClient) Subject(ctx context.Context, typ, id string) ([]byte, error)

Subject fetches a subject of the given Frodo type ("movie", "book", "music", "game"). Movie covers TV as well.

func (*FrodoClient) UserAgent added in v0.2.0

func (f *FrodoClient) UserAgent() string

UserAgent returns the User-Agent the client sends. Frodo rejects requests that do not identify the app, so this must remain an app UA.

type FrodoConfig added in v0.2.0

type FrodoConfig struct {
	// BaseURL overrides the API origin for tests. Empty means DefaultFrodoBase.
	BaseURL   string
	APIKey    string
	Secret    string
	UserAgent string
	Rate      time.Duration
	Timeout   time.Duration
	Retries   int
}

FrodoConfig configures a FrodoClient.

func DefaultFrodoConfig added in v0.2.0

func DefaultFrodoConfig() FrodoConfig

DefaultFrodoConfig returns a working configuration. The Frodo host tolerates a faster pace than the web hosts, so Rate defaults below the web Crawl-delay.

type FrodoError added in v0.2.0

type FrodoError struct {
	Status    int    `json:"-"`
	Code      int    `json:"code"`
	Request   string `json:"request"`
	Msg       string `json:"msg"`
	Localized string `json:"localized_message"`
}

FrodoError is the API's error envelope: a JSON body carrying a numeric code, e.g. 996 (signature error), 997 (unknown apikey), 1062 (rate limited).

func (*FrodoError) Error added in v0.2.0

func (e *FrodoError) Error() string

type Movie added in v0.2.0

type Movie struct {
	Rank      int    `json:"rank,omitempty"`
	ID        string `json:"id"`
	Title     string `json:"title"`
	AKA       string `json:"aka,omitempty"`
	Year      string `json:"year,omitempty"`
	Region    string `json:"region,omitempty"`
	Genres    string `json:"genres,omitempty"`
	Directors string `json:"directors,omitempty"`
	Cast      string `json:"cast,omitempty" table:",truncate"`
	Duration  string `json:"duration,omitempty"`
	Rating    string `json:"rating"`
	URL       string `json:"url"`
	Cover     string `json:"cover,omitempty" table:",truncate"`
	Quote     string `json:"quote,omitempty" table:",truncate"`
}

Movie is a unified film record; fields a given surface does not carry are omitted from output.

type Result

type Result struct {
	Rank     int    `json:"rank"`
	ID       string `json:"id"`
	Type     string `json:"type"`
	Title    string `json:"title"`
	Rating   string `json:"rating"`
	Abstract string `json:"abstract" table:",truncate"`
	URL      string `json:"url"`
	Cover    string `json:"cover,omitempty" table:",truncate"`
}

Result is the record emitted for every search hit.

type Suggestion added in v0.2.0

type Suggestion struct {
	ID       string `json:"id"`
	Type     string `json:"type"`
	Title    string `json:"title"`
	SubTitle string `json:"sub_title,omitempty"`
	Year     string `json:"year,omitempty"`
	URL      string `json:"url"`
	Img      string `json:"img,omitempty" table:",truncate"`
}

Suggestion is the record emitted for every suggest hit.

Jump to

Keyboard shortcuts

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