iawia002/lux · error

请先购买课程,或使用Cookie登录。

Error message

请先购买课程,或使用Cookie登录。

What it means

The GeekBang article API responded successfully but with an empty VideoID and ColumnHadSub=false: the account behind the supplied cookie has not purchased this paid column, or no cookie reached the request at all. The Chinese message translates to 'Please purchase the course first, or log in with Cookie.'

Source

Thrown at extractors/geekbang/geekbang.go:113

	heanders := map[string]string{"Origin": "https://time.geekbang.org", "Content-Type": "application/json", "Referer": url}
	params := strings.NewReader(fmt.Sprintf(`{"id": %q}`, matches[2]))
	res, err := request.Request(http.MethodPost, "https://time.geekbang.org/serv/v1/article", params, heanders)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	defer res.Body.Close() // nolint

	var data geekData
	if err = json.NewDecoder(res.Body).Decode(&data); err != nil {
		return nil, errors.WithStack(err)
	}

	if data.Code < 0 {
		return nil, errors.New(string(data.Error))
	}

	if data.Data.VideoID == "" && !data.Data.ColumnHadSub {
		return nil, errors.New("请先购买课程,或使用Cookie登录。")
	}

	// Get video license token information
	params = strings.NewReader("{\"source_type\":1,\"aid\":" + matches[2] + ",\"video_id\":\"" + data.Data.VideoID + "\"}")
	res, err = request.Request(http.MethodPost, "https://time.geekbang.org/serv/v3/source_auth/video_play_auth", params, heanders)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	defer res.Body.Close() // nolint

	var playAuth videoPlayAuth
	if err = json.NewDecoder(res.Body).Decode(&playAuth); err != nil {
		return nil, errors.WithStack(err)
	}

	if playAuth.Code < 0 {
		return nil, errors.New(string(playAuth.Error))
	}

View on GitHub (pinned to dd00f6d258)

Solutions

  1. Log in with the purchasing account, export its cookie, and pass it via -c.
  2. Verify in a browser (same account) that the video actually plays.
  3. If you do own the course, re-export the cookie — stale sessions also land here.

Example fix

// before
$ lux "https://time.geekbang.org/column/article/123456"
// after
$ lux -c cookie-purchased-account.txt "https://time.geekbang.org/column/article/123456"
Defensive patterns

Strategy: try-catch

Type guard

func isGeekbangPurchaseRequired(err error) bool {
	return err != nil && strings.Contains(err.Error(), "请先购买课程")
}

Try / catch

Catch and branch on the message: purchase/login prompt means credential or entitlement problems — re-authenticate with the purchasing account and retry. Do not retry with the same cookie; it cannot succeed.

Prevention

When it happens

Trigger: Running without -c; a cookie belonging to an account without the subscription; free-preview articles whose full video requires purchase.

Common situations: Assuming an article link is free; stale exported cookies; team members sharing links but not entitlements.

Related errors


AI-assisted analysis of iawia002/lux@dd00f6d258 (2026-08-15). Data as JSON: /api/errors/cd94c516dc0d20a6. Report an issue: GitHub.