archive

package
v0.2.2 Latest Latest
Warning

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

Go to latest
Published: Jun 19, 2026 License: AGPL-3.0 Imports: 13 Imported by: 0

Documentation

Overview

Package archive is the capture pipeline that turns a target into a tori repository: it plans what to fetch on the cheapest free tier, streams the records through the x-cli engine into the store, localises the media, renders the HTML and Markdown views, and writes the manifest (spec §5, §7). It owns no scraping of its own — every byte from X comes through the x-cli engine (TP1) — and no presentation — every page comes through render/ (TP3). What it adds is the artifact: a self-contained, deterministic, resumable archive.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Kind

type Kind string

Kind is what a capture target points at (spec §6.5, §7).

const (
	KindTweet     Kind = "tweet"
	KindThread    Kind = "thread"
	KindProfile   Kind = "profile"
	KindSearch    Kind = "search"
	KindBookmarks Kind = "bookmarks"
	KindLikes     Kind = "likes"
	KindList      Kind = "list"
)

type Logf

type Logf func(format string, args ...any)

Logf is the optional progress sink the capture writes human-readable lines to. The CLI passes a function that prints to stderr; a nil Logf is silent, which is what the tests use so they stay quiet and deterministic.

type Options

type Options struct {
	// Output.
	Out   string   // output root; the repo lands at <Out>/x/<root>
	Views []string // which rendered shapes to write: "html", "md"

	// Media.
	Media     media.Policy    // all | photos | none
	Video     media.VideoPref // best | worst
	VideoKbps int             // when >0, pick the rendition nearest this bitrate (overrides Video)
	Tool      string          // optional external downloader for stream-only video (e.g. yt-dlp)

	// Record shaping.
	Max          int  // hard record budget; 0 means as many as the tier gives
	Thread       bool // upgrade a tweet target into a full-conversation capture
	WithReplies  bool // include replies in a profile/timeline capture
	WithRetweets bool // include retweets in a profile/timeline capture
	MediaOnly    bool // only tweets carrying media

	// Timeline bounds.
	Since   time.Time // only tweets at or after this time
	Until   time.Time // only tweets before this time
	SinceID string    // only tweets newer than this id
	UntilID string    // only tweets older than this id

	// Full-history exhaustion. A user timeline caps at roughly 3200 tweets, so to
	// archive an account's whole history tori walks month-wide search windows
	// (from:<handle> since:.. until:..) from the account's creation to now,
	// stitching the results into one timeline (spec §7.1). Requires a GraphQL tier.
	ByMonth bool

	// Link chasing (bounded), via x.Walk.
	Depth  int
	Fanout int

	// Run control.
	Date    time.Time // capture stamp written into the manifest (TP5); zero means now
	Resume  bool      // continue from state.json when present (default on)
	Force   bool      // ignore held state and re-capture from scratch
	DryRun  bool      // plan only; fetch and write nothing
	Verbose bool      // log the tier and endpoint per record
	Version string    // tori build version, recorded in the manifest
}

Options is the resolved configuration for one capture, built from the CLI flags. The zero value is not valid; the CLI fills it. Fetch-shaping fields mirror the x-cli timeline/search readers so a tori flag maps straight onto an engine call (spec §12.1).

type RenderOptions

type RenderOptions struct {
	Views   []string  // which shapes to write: "html", "md"
	Date    time.Time // footer stamp; zero means now
	Version string
}

RenderOptions controls a re-render of an existing repository.

type RenderResult

type RenderResult struct {
	Total   int
	Threads int
}

RenderResult summarises a re-render.

func Render

func Render(root string, o RenderOptions) (*RenderResult, error)

Render re-renders the views of an existing repository from its stored JSON, touching no network (spec §5). It reads the records, the profile, and the manifest's media index (so localised media still resolves), reconstructs the threads, and writes the requested views over the existing ones.

type Result

type Result struct {
	Root       string   // repository directory written
	Target     Target   // what was captured
	Profile    *User    // the captured profile, when the target had one
	Added      int      // tweets newly written this run
	Total      int      // tweets in the repo after this run
	Threads    int      // reconstructed conversations
	MediaOK    int      // media files on disk after this run
	MediaFail  int      // media references that could not be localised
	StreamOnly int      // video with no progressive rendition
	Tiers      []string // tiers that served this capture
	Oldest     string   // oldest captured tweet timestamp (RFC3339), empty if none
	Newest     string   // newest captured tweet timestamp
	DryRun     bool     // true when nothing was fetched or written
	Windows    int      // month-windows walked for a full-history profile capture
	// contains filtered or unexported fields
}

Result summarises a completed capture for the CLI to print and for the exit code to reflect (a partial capture with failures is still a success on disk).

func Run

func Run(ctx context.Context, eng *x.Engine, t Target, opts Options, log Logf) (*Result, error)

Run captures a target into a repository under opts.Out and returns a summary. It is the one entry the CLI's archive/add commands call. The pipeline is: resolve and stream records into the store (writing each as it arrives so a session-limited or interrupted run keeps what it got), localise media, render the requested views, and write the manifest. Records always persist as JSON; media and views are derived and regenerable with `tori render`.

func (*Result) Note

func (r *Result) Note(format string, args ...any)

Note records a one-line degradation or hint for the CLI to surface (e.g. a Tier-0 capture that --guest would page deeper).

func (*Result) Notes

func (r *Result) Notes() []string

Notes returns the accumulated notes.

type Selector

type Selector struct {
	Thread    bool
	Search    string
	Bookmarks bool
	Likes     string
	List      string
}

Selector carries the flags that pick a non-profile target kind, so a bare argument is read in the light of --search/--bookmarks/--likes/--list/--thread (spec §12.1). Exactly one of the kind-selecting fields may be set.

type Target

type Target struct {
	Kind    Kind
	Ref     string
	Display string
}

Target is a parsed, canonical capture target. Ref is the canonical identity used to both address the source and name the repository root: a profile's handle, a tweet/thread/list id, or a search query. Display is a human label for the page nav and headings.

func ParseTarget

func ParseTarget(arg string, sel Selector) (Target, error)

ParseTarget resolves a CLI argument and the kind-selecting flags into a canonical Target. The grammar is x-cli's own ref grammar (TP via ParseTweetRef / ParseUserRef) plus tori's capture keywords: a status URL or numeric id is a tweet (a thread with --thread), a @handle or profile URL is a profile, and the --search/--bookmarks/--likes/--list flags select the timeline kinds. arg may be empty when a flag fully specifies the target (--bookmarks, --search).

func (Target) Root

func (t Target) Root(out string) string

Root returns the repository directory for this target under out: out/x/<root>, where <root> is the canonical, filesystem-safe target identity (spec §6.1). Two captures of the same target land in the same repo and merge.

func (Target) TargetRef

func (t Target) TargetRef() repo.TargetRef

TargetRef converts the parsed target into the manifest's record of what the repository archives.

type User

type User = x.User

User aliases the engine's profile type so the Result reads naturally without a second import at every call site.

Jump to

Keyboard shortcuts

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