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
- Variables
- func Defaults(c *kit.Config)
- func Identity() kit.Identity
- type Book
- type Client
- func (c *Client) Book(ctx context.Context, idOrURL string) (*Book, error)
- func (c *Client) Chart(ctx context.Context) ([]Movie, error)
- func (c *Client) Doulist(ctx context.Context, idOrURL string, limit int) ([]DoulistItem, error)
- func (c *Client) Get(ctx context.Context, rawURL string) ([]byte, error)
- func (c *Client) NowPlaying(ctx context.Context, city string, coming bool, limit int) ([]Movie, error)
- func (c *Client) Search(ctx context.Context, query, searchType string, limit int) ([]Result, error)
- func (c *Client) Suggest(ctx context.Context, query, suggestType string, limit int) ([]Suggestion, error)
- func (c *Client) Top250(ctx context.Context, limit int) ([]Movie, error)
- type Config
- type Domain
- type DoulistItem
- type FrodoClient
- func (f *FrodoClient) Book(ctx context.Context, id string) ([]byte, error)
- func (f *FrodoClient) Celebrities(ctx context.Context, id string) ([]byte, error)
- func (f *FrodoClient) Game(ctx context.Context, id string) ([]byte, error)
- func (f *FrodoClient) Get(ctx context.Context, path string, params url.Values) ([]byte, error)
- func (f *FrodoClient) Interests(ctx context.Context, typ, id string, start, count int) ([]byte, error)
- func (f *FrodoClient) Movie(ctx context.Context, id string) ([]byte, error)
- func (f *FrodoClient) Music(ctx context.Context, id string) ([]byte, error)
- func (f *FrodoClient) Personage(ctx context.Context, id string) ([]byte, error)
- func (f *FrodoClient) Photos(ctx context.Context, typ, id string, start, count int) ([]byte, error)
- func (f *FrodoClient) Rating(ctx context.Context, typ, id string) ([]byte, error)
- func (f *FrodoClient) Reviews(ctx context.Context, typ, id string, start, count int) ([]byte, error)
- func (f *FrodoClient) SearchSubjects(ctx context.Context, q string, start, count int) ([]byte, error)
- func (f *FrodoClient) Subject(ctx context.Context, typ, id string) ([]byte, error)
- func (f *FrodoClient) UserAgent() string
- type FrodoConfig
- type FrodoError
- type Movie
- type Result
- type Suggestion
Constants ¶
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 */ )
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 ¶
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.
var ErrNotFound = errors.New("douban: not found")
ErrNotFound is returned when Douban has no subject, list, or page for an id.
Functions ¶
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
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 (*Client) Book ¶ added in v0.2.0
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
Chart returns the current Douban film ranking board (/chart).
func (*Client) Doulist ¶ added in v0.2.0
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
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 ¶
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.
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.
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.
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) Celebrities ¶ added in v0.2.0
Celebrities returns the directors/actors credit list for a movie.
func (*FrodoClient) Get ¶ added in v0.2.0
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
Movie, Book, Music, Game fetch a subject detail of that type.
func (*FrodoClient) Personage ¶ added in v0.2.0
Personage fetches the rich celebrity/personage profile (elessar subject).
func (*FrodoClient) Rating ¶ added in v0.2.0
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
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.