Help us shape the future of Go! Take the 2026 Go Developer Survey

booksource

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: Apache-2.0 Imports: 38 Imported by: 0

Documentation

Overview

Package booksource implements a Go reader for Legado-compatible source definitions.

Index

Constants

This section is empty.

Variables

View Source
var ErrJSTimeout = errors.New("JavaScript执行超时")

Functions

func LoadCachedContent

func LoadCachedContent(dataDir string, book Book, chapter Chapter) (string, error)

func MatchAlternativeChapter

func MatchAlternativeChapter(chapters []Chapter, previousTitle string, previousIndex int) (index int, matched bool)

MatchAlternativeChapter uses only unique matches. When no reliable title or chapter number exists, the caller must disclose that the clamped index is an approximation rather than an identified chapter.

func NormalizeContent

func NormalizeContent(text string) string

NormalizeContent converts common HTML fragments to readable chapter text. Unknown angle-bracket words are preserved; this is not an HTML sanitizer. Entity decoding is bounded to three layers for escaped source responses.

func SaveCachedChapters

func SaveCachedChapters(dataDir string, book Book, chapters []Chapter) error

func SaveCachedContent

func SaveCachedContent(dataDir string, book Book, chapter Chapter, content string) error

func SaveSources

func SaveSources(dataDir string, sources []Source) error

func SourceDefinitionFingerprint

func SourceDefinitionFingerprint(source Source) string

Personal preferences and display names do not change the rules being checked.

func SourceGroups

func SourceGroups(source Source) []string

func SourceKey

func SourceKey(source Source) string

func ValidateSource

func ValidateSource(source Source) error

Types

type AlternativeResult

type AlternativeResult struct {
	Books  []Book
	Errors []string
}

AlternativeResult retains successful candidates when individual sources fail.

type Book

type Book struct {
	Variables   map[string]any `json:"variables,omitempty"`
	SourceURL   string         `json:"source_url"`
	SourceName  string         `json:"source_name"`
	URL         string         `json:"url"`
	TOCURL      string         `json:"toc_url,omitempty"`
	Name        string         `json:"name"`
	Author      string         `json:"author,omitempty"`
	Intro       string         `json:"intro,omitempty"`
	CoverURL    string         `json:"cover_url,omitempty"`
	Kind        string         `json:"kind,omitempty"`
	LastChapter string         `json:"last_chapter,omitempty"`
}

type BookRule

type BookRule struct {
	Init        string `json:"init,omitempty"`
	BookList    string `json:"bookList,omitempty"`
	Name        string `json:"name,omitempty"`
	Author      string `json:"author,omitempty"`
	BookURL     string `json:"bookUrl,omitempty"`
	TOCURL      string `json:"tocUrl,omitempty"`
	CoverURL    string `json:"coverUrl,omitempty"`
	Intro       string `json:"intro,omitempty"`
	Kind        string `json:"kind,omitempty"`
	LastChapter string `json:"lastChapter,omitempty"`
}

type Chapter

type Chapter struct {
	NextURL string `json:"next_url,omitempty"`
	Name    string `json:"name"`
	URL     string `json:"url"`
}

func LoadCachedChapters

func LoadCachedChapters(dataDir string, book Book) ([]Chapter, error)

type Client

type Client struct {
	HTTPClient       *http.Client
	MaxResponseBytes int64
	MaxPages         int
	// contains filtered or unexported fields
}

func NewClient

func NewClient() *Client

func (*Client) BookInfo

func (c *Client) BookInfo(ctx context.Context, source Source, book Book) (Book, error)

func (*Client) Chapters

func (c *Client) Chapters(ctx context.Context, source Source, book Book) ([]Chapter, error)

func (*Client) CheckSource

func (c *Client) CheckSource(ctx context.Context, source Source, keyword string, deep bool) (result SourceCheckResult)

CheckSource checks a source without enabling, disabling or removing it. An empty keyword performs syntax checks only; scripts are never evaluated.

func (*Client) Content

func (c *Client) Content(ctx context.Context, source Source, book Book, chapter Chapter) (string, error)

func (*Client) FindAlternatives

func (c *Client) FindAlternatives(ctx context.Context, sources []Source, current Book, page int) (AlternativeResult, error)

FindAlternatives searches every enabled, searchable text source. Candidate order follows the source order, then the order returned by each source.

func (*Client) Import

func (c *Client) Import(ctx context.Context, location string) ([]Source, error)

func (*Client) IsLoggedIn

func (c *Client) IsLoggedIn(src Source) bool

func (*Client) LoadSessions

func (c *Client) LoadSessions(dir string) error

func (*Client) Login

func (c *Client) Login(ctx context.Context, src Source, fields map[string]string) error

Login supports the declared 大灰狼 API profile and manual website cookies. Credentials are scoped to one explicitly declared API origin, are never passed to source JavaScript and are never written to the session file.

func (*Client) LoginStatus

func (c *Client) LoginStatus(src Source) bool

func (*Client) Logout

func (c *Client) Logout(src Source) error

func (*Client) SaveSessions

func (c *Client) SaveSessions(dir string) error

func (*Client) Search

func (c *Client) Search(ctx context.Context, source Source, keyword string, page int) ([]Book, error)

type ContentRule

type ContentRule struct {
	Content        string `json:"content"`
	NextContentURL string `json:"nextContentUrl,omitempty"`
	ReplaceRegex   string `json:"replaceRegex,omitempty"`
}

type Evaluator

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

Evaluator implements the portable subset of Legado's source rule language. Each JavaScript invocation has its own VM; put/get variables are shared by this evaluator. Selectors return detached values or HTML nodes for chaining.

func NewEvaluator

func NewEvaluator(baseURL string, variables map[string]any) *Evaluator

func (*Evaluator) Elements

func (e *Evaluator) Elements(input any, rule string) ([]any, error)

func (*Evaluator) EvalJS

func (e *Evaluator) EvalJS(code string, result any) (output any, evalErr error)

EvalJS exposes only portable helpers and explicitly granted JS bindings. Android/Rhino-specific APIs fail at the point of use with a named error.

func (*Evaluator) SetJSBindings

func (e *Evaluator) SetJSBindings(bindings map[string]any) *Evaluator

SetJSBindings explicitly grants scripts trusted application capabilities. A java map augments the built-in helpers. Callers must bound any blocking native function (for example with HTTP context deadlines); VM interruption cannot preempt a Go function. Treat the supplied maps as immutable.

func (*Evaluator) SetJSContext

func (e *Evaluator) SetJSContext(ctx context.Context) *Evaluator

SetJSContext binds script execution to the request lifetime. Native bindings must use this same request context for their own blocking operations.

func (*Evaluator) SetJSLib

func (e *Evaluator) SetJSLib(code string) *Evaluator

func (*Evaluator) SetJSTimeout

func (e *Evaluator) SetJSTimeout(timeout time.Duration) *Evaluator

func (*Evaluator) String

func (e *Evaluator) String(input any, rule string) (string, error)

func (*Evaluator) Strings

func (e *Evaluator) Strings(input any, rule string) ([]string, error)

type ImportPreview

type ImportPreview struct {
	Sources     []Source
	Added       int
	Updated     int
	Unsupported int
	Collection  SourceCollection
}

func BuildImportPreview

func BuildImportPreview(existing, incoming []Source, location string) ImportPreview

BuildImportPreview never modifies either input. Last duplicate URL wins while keeping its first position. Imported readcli data is deliberately discarded.

type LoginField

type LoginField struct {
	Name   string
	Secret bool
}

LoginField describes an input supported by this client. Script buttons that register accounts, purchase content or change server settings are not run.

func LoginFields

func LoginFields(src Source) []LoginField

func LoginUIFields

func LoginUIFields(src Source) []LoginField

type Source

type Source struct {
	Management   *SourceManagement          `json:"readcli,omitempty"`
	LoginURL     string                     `json:"loginUrl,omitempty"`
	LoginUI      json.RawMessage            `json:"loginUi,omitempty"`
	LoginCheckJS string                     `json:"loginCheckJs,omitempty"`
	Extra        map[string]json.RawMessage `json:"-"`
	URL          string                     `json:"bookSourceUrl"`
	Name         string                     `json:"bookSourceName"`
	Group        string                     `json:"bookSourceGroup,omitempty"`
	Type         int                        `json:"bookSourceType"`
	Enabled      *bool                      `json:"enabled,omitempty"`
	Header       json.RawMessage            `json:"header,omitempty"`
	JSLib        string                     `json:"jsLib,omitempty"`
	SearchURL    string                     `json:"searchUrl"`
	Search       BookRule                   `json:"ruleSearch"`
	BookInfo     BookRule                   `json:"ruleBookInfo"`
	TOC          TOCRule                    `json:"ruleToc"`
	Content      ContentRule                `json:"ruleContent"`
}

func ApplyImport

func ApplyImport(existing []Source, preview ImportPreview, selected map[string]bool, enableNew bool) []Source

ApplyImport imports only explicitly selected URL keys; nil selects nothing. Existing enablement and local metadata win over downloaded settings.

func CloneSources

func CloneSources(sources []Source) []Source

CloneSources preserves nil slices and copies all mutable source data. It does not serialize, so unknown fields survive even when their raw JSON is invalid.

func Import

func Import(ctx context.Context, location string) ([]Source, error)

Import accepts a UTF-8 JSON file or HTTP(S) URL. Malformed entries are reported with their array position. Valid unsupported sources are retained disabled so an imported collection can round-trip without losing entries.

func LoadSources

func LoadSources(dataDir string) ([]Source, error)

func MergeSources

func MergeSources(existing, incoming []Source) []Source

MergeSources keeps the original API for callers without import collections. Downloaded rules replace matching URLs; local preferences remain authoritative.

func RemoveCollection

func RemoveCollection(sources []Source, id string) (remaining []Source, removed int, shared int)

RemoveCollection removes only sources whose final collection is removed. Legacy sources with no collection membership are left untouched.

func (Source) IsEnabled

func (s Source) IsEnabled() bool

func (Source) MarshalJSON

func (s Source) MarshalJSON() ([]byte, error)

func (*Source) UnmarshalJSON

func (s *Source) UnmarshalJSON(data []byte) error

Some source exports serialize individual rule objects as JSON strings.

type SourceCheckResult

type SourceCheckResult struct {
	Status     string    `json:"status"`
	Stage      string    `json:"stage"`
	Detail     string    `json:"detail"`
	CheckedAt  time.Time `json:"checked_at"`
	DurationMS int64     `json:"duration_ms"`
}

SourceCheckResult records one manual check without changing source settings.

type SourceCollection

type SourceCollection struct {
	ID         string    `json:"id"`
	Name       string    `json:"name"`
	ImportedAt time.Time `json:"imported_at"`
}

type SourceManagement

type SourceManagement struct {
	Standalone  bool               `json:"standalone,omitempty"`
	Favorite    bool               `json:"favorite,omitempty"`
	Tags        []string           `json:"tags,omitempty"`
	Collections []SourceCollection `json:"collections,omitempty"`
	Check       *SourceCheckResult `json:"check,omitempty"`
}

SourceManagement belongs to this installation, never to a downloaded source. It is stored with the source so one atomic write includes rules and settings.

type TOCRule

type TOCRule struct {
	ChapterList string `json:"chapterList"`
	ChapterName string `json:"chapterName"`
	ChapterURL  string `json:"chapterUrl"`
	NextTOCURL  string `json:"nextTocUrl,omitempty"`
	IsVolume    string `json:"isVolume,omitempty"`
}

Jump to

Keyboard shortcuts

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