Documentation
¶
Index ¶
Constants ¶
const CurrentVersion = 1
CurrentVersion is the schema version Save stamps into the state file. Bump it when an entry field changes meaning (not when one is merely added — additions unmarshal cleanly from older files). Past migrations (UpdatedAt backfill, Price int→float64) had to be inferred from data shape; an explicit version makes the next one a comparison.
const FileName = "_state.json"
FileName is the name of the state file in each blog directory.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type PostEntry ¶
type PostEntry struct {
Title string `json:"title"`
DirName string `json:"dirName"`
DownloadedAt string `json:"downloadedAt"`
UpdatedAt int64 `json:"updatedAt,omitempty"`
CommentsCount int `json:"commentsCount"`
Price float64 `json:"price"`
Tier string `json:"tier,omitempty"`
Locked bool `json:"locked,omitempty"`
HasComments bool `json:"hasComments"`
HasMd bool `json:"hasMd"`
// CommentsCapped records that this post hit the comments-fetch ceiling
// the last time it was saved. The ceiling is our choice forced by a
// broken offset query param on Boosty's comments endpoint (offset>0
// returns data=[] with isLast=true), so we cannot paginate past the
// first page and we cap at commentsPageLimit-1 top-level threads or
// defaultReplyLimit inlined replies per thread — see
// pkg/syncer/save.go commentsPageLimit and pkg/boosty/client.go
// defaultReplyLimit. Without this flag, classifyPost would re-fire
// NewComments on every sync forever because disk count can never catch
// up to API count. With it, classify skips the disk<API trigger
// (suppression is one-directional — see pkg/syncer/classify.go).
CommentsCapped bool `json:"commentsCapped,omitempty"`
}
PostEntry records metadata about a downloaded post.
type State ¶
type State struct {
// Version is the schema version of the file on disk. 0 means a legacy
// file written before the field existed — loaded fine, upgraded to
// CurrentVersion on the next Save.
Version int `json:"version"`
Posts map[string]PostEntry `json:"posts"`
LastSync string `json:"lastSync"`
// contains filtered or unexported fields
}
State tracks which posts have been downloaded for a blog.
State is NOT safe for concurrent use; callers that mutate it from multiple goroutines (e.g. the --workers > 1 download pool) must serialise access through their own mutex. The in-memory operations (Has, Get, Add, Count) are plain map access and never lock on their own.
func Load ¶
Load reads the state file from the given directory. A missing state file is reported as a fresh, empty state (nil error). Read or parse errors are returned so callers can refuse to overwrite a partially-recoverable `_state.json` with a freshly-initialised one — which would discard every previously tracked post.
The Posts map is always non-nil on a successful return so callers can use it directly. The JSON nil-check after Unmarshal is intentional — a payload of `{"posts": null}` would otherwise leave the map nil and panic on the first Add.