Documentation
¶
Overview ¶
Package tiktok is the library behind the tt command line: the HTTP client, the SSR blob parsing, the signed API calls, and the typed data models.
Two planes feed the records. The SSR plane reads the __UNIVERSAL_DATA_FOR_REHYDRATION__ JSON a logged-out page ships and needs no signing. The API plane calls www.tiktok.com/api/* with an X-Bogus signature and an msToken. The API plane sits behind a Web Application Firewall that scores the caller; when it wins, the client returns ErrWalled so the command layer can report it honestly instead of a silent empty result.
Index ¶
- Constants
- Variables
- func BaseIdentity() kit.Identity
- func Defaults(c *kit.Config)
- func IsSecUID(s string) bool
- func MapErr(err error) error
- func ParseHandle(in string) (string, error)
- func ParseMusicID(in string) (string, error)
- func ParseVideoID(in string) (string, error)
- func Register(app *kit.App)
- type Client
- func (c *Client) Comments(ctx context.Context, videoID, author string, limit int) ([]Comment, error)
- func (c *Client) GetAPI(ctx context.Context, path, rawQuery string) ([]byte, error)
- func (c *Client) GetPage(ctx context.Context, url string) (string, error)
- func (c *Client) HashtagByName(ctx context.Context, name string) (Hashtag, error)
- func (c *Client) HashtagVideos(ctx context.Context, challengeID string, limit int) ([]Video, error)
- func (c *Client) Posts(ctx context.Context, handle string, limit int, cursor string) ([]Video, error)
- func (c *Client) RawUniversal(ctx context.Context, url string) ([]byte, error)
- func (c *Client) Related(ctx context.Context, videoID string, limit int) ([]Video, error)
- func (c *Client) Replies(ctx context.Context, videoID, commentID, author string, limit int) ([]Comment, error)
- func (c *Client) Search(ctx context.Context, keyword string, limit int) ([]SearchHit, error)
- func (c *Client) SoundByID(ctx context.Context, slug, id string) (Sound, error)
- func (c *Client) SoundVideos(ctx context.Context, musicID string, limit int) ([]Video, error)
- func (c *Client) Trending(ctx context.Context, limit int) ([]Video, error)
- func (c *Client) UserAgent() string
- func (c *Client) UserByHandle(ctx context.Context, handle string) (User, error)
- func (c *Client) Users(ctx context.Context, keyword string, limit int) ([]User, error)
- func (c *Client) VideoByID(ctx context.Context, author, id string) (Video, error)
- type Comment
- type Config
- type CrawlOptions
- type Crawler
- type Domain
- type Edge
- type Hashtag
- type Node
- type SearchHit
- type Seed
- type SeedKind
- type Session
- type Sound
- type Source
- type Summary
- type User
- type Video
Constants ¶
const ( KindUser = "user" KindVideo = "video" KindHashtag = "hashtag" KindSound = "sound" )
Node kinds carried by the discovery walk.
const DefaultUserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
DefaultUserAgent is a current desktop Chrome string. An honest, real User-Agent is both polite and the thing most likely to keep a session unblocked.
const Host = "https://www.tiktok.com"
Host is the web origin every request targets.
Variables ¶
var ErrNotFound = errors.New("not found")
ErrNotFound means the page parsed but carried no record for the request, for example a handle that does not exist or a private profile with no items.
var ErrWalled = errors.New("tiktok served a WAF challenge (this surface needs a residential session)")
ErrWalled means the WAF served a challenge or a signed call came back empty. The surface needs a residential session.
Functions ¶
func BaseIdentity ¶ added in v0.2.0
BaseIdentity is the help and version identity shared by the standalone binary and any host that links the package.
func Defaults ¶ added in v0.2.0
Defaults seeds the framework baseline from the tiktok defaults, so an unset --rate/--retries/--timeout keeps the library's own pacing.
func IsSecUID ¶
IsSecUID reports whether s looks like a TikTok secUid rather than a handle. A secUid is a long opaque token starting with "MS4wLjAB".
func MapErr ¶ added in v0.2.0
mapErr converts a library error into the kit error kind that carries the right exit code, so a host renders the same walled and not-found outcomes the standalone binary does. A WAF challenge is exit 4 (needs a residential session), a missing record is exit 6.
func ParseHandle ¶
ParseHandle pulls a bare @handle out of "tiktok", "@tiktok", or a full profile url.
func ParseMusicID ¶
ParseMusicID pulls a numeric sound id out of a /music/{slug}-{id} url, or accepts a bare numeric id.
func ParseVideoID ¶
ParseVideoID pulls a numeric video id out of a /video/{id} or /photo/{id} url, or accepts a bare numeric id.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client talks to TikTok over HTTP.
func (*Client) Comments ¶
func (c *Client) Comments(ctx context.Context, videoID, author string, limit int) ([]Comment, error)
Comments pages the comment list under a video. author builds the url field.
func (*Client) GetAPI ¶
GetAPI signs an /api/{path} call, fetches it, and returns the JSON body. An empty body on a 200 is the WAF gating the call, so it maps to ErrWalled.
func (*Client) GetPage ¶
GetPage fetches an SSR page and returns its body. It detects the WAF challenge stub and returns ErrWalled for it.
func (*Client) HashtagByName ¶
HashtagByName fetches a tag page and returns its Hashtag record.
func (*Client) HashtagVideos ¶
HashtagVideos pages the videos under a challenge id.
func (*Client) Posts ¶
func (c *Client) Posts(ctx context.Context, handle string, limit int, cursor string) ([]Video, error)
Posts pages a user's videos through post/item_list. handle may be a @handle or a secUid. It returns up to limit videos (0 means one page).
func (*Client) RawUniversal ¶
RawUniversal fetches a page and returns its rehydration blob as pretty JSON.
func (*Client) Related ¶
Related pages the videos TikTok recommends alongside one video, through related/item_list. It returns up to limit videos (0 means one page). The discovery walk uses it as a video-to-video edge.
func (*Client) Replies ¶
func (c *Client) Replies(ctx context.Context, videoID, commentID, author string, limit int) ([]Comment, error)
Replies pages the replies under one comment.
func (*Client) SoundVideos ¶
SoundVideos pages the videos using a sound id.
func (*Client) UserByHandle ¶
UserByHandle fetches a profile page and returns its User record.
type Comment ¶
type Comment struct {
ID string `json:"id" kit:"id"`
VideoID string `json:"video_id"`
Text string `json:"text" kit:"body" table:"text,truncate"`
Author string `json:"author"`
AuthorID string `json:"author_id"`
AuthorNick string `json:"author_nick"`
CreateTime int64 `json:"create_time"`
DiggCount int64 `json:"digg_count"`
ReplyCount int64 `json:"reply_count"`
ParentID string `json:"parent_id"`
URL string `json:"url"`
}
Comment is one comment under a video, with its parent id for replies.
type Config ¶
Config holds the tunable client settings.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns polite defaults: a 600ms gap between requests, a 30s timeout, and five retries on transient errors.
type CrawlOptions ¶
type CrawlOptions struct {
Depth int // maximum hops from a seed
MaxNodes int // stop after this many nodes are emitted
MaxRequests int // stop after this many source calls
Deadline time.Duration // wall-clock cap, 0 means off
Fanout int // neighbors taken per list-bearing node
CommentMine int // commenters mined per video, 0 means off
Decay float64 // per-hop score decay applied to the frontier
Now func() time.Time
}
CrawlOptions bounds and tunes a walk. Zero values take sane defaults.
type Crawler ¶
type Crawler struct {
Src Source
Opts CrawlOptions
OnNode func(Node) // called as each node with data is emitted
OnEdge func(Edge) // optional, called as each edge is walked
}
Crawler walks the public graph from seeds, scoring as it goes.
type Domain ¶ added in v0.2.0
type Domain struct{}
Domain is the TikTok driver. It carries no state; the per-run client is built by the factory Register hands kit.
func (Domain) Classify ¶ added in v0.2.0
Classify turns any accepted input into the canonical (type, id), so `ant resolve` and `ant url` need no network. A bare handle, a /video/ link, a /tag/ link, and a /music/ link each map to their resource type.
func (Domain) Info ¶ added in v0.2.0
func (Domain) Info() kit.DomainInfo
Info describes the scheme, the hostnames a pasted link is matched against, and the identity a host reuses for help and version.
func (Domain) Locate ¶ added in v0.2.0
Locate is the inverse: the live https URL for a (type, id), built without a fetch.
type Edge ¶
type Edge struct {
FromID string `json:"from_id"`
FromKind string `json:"from_kind"`
ToID string `json:"to_id"`
ToKind string `json:"to_kind"`
Type string `json:"type"`
}
Edge records that expanding From led to To along Type.
type Hashtag ¶
type Hashtag struct {
ID string `json:"id"`
Title string `json:"title" kit:"id"`
Desc string `json:"desc" kit:"body" table:"desc,truncate"`
VideoCount int64 `json:"video_count"`
ViewCount int64 `json:"view_count"`
Cover string `json:"cover"`
URL string `json:"url"`
}
Hashtag is a challenge page header, addressed by its name.
type Node ¶
type Node struct {
Kind string
ID string
Depth int
Via string
Score float64
User *User
Video *Video
Hashtag *Hashtag
Sound *Sound
}
Node is one reached graph node. Exactly one record pointer is set per Kind.
type SearchHit ¶
type SearchHit struct {
Type string `json:"type"`
ID string `json:"id" kit:"id"`
Title string `json:"title" table:"title,truncate"`
Author string `json:"author"`
URL string `json:"url"`
}
SearchHit is a thin, normalized search result row.
type Session ¶ added in v0.2.0
Session is the per-run client kit injects into every operation. It pairs the HTTP client with the resolved quiet flag, so an operation can pace its own stderr progress without reaching for a global.
type Sound ¶
type Sound struct {
ID string `json:"id" kit:"id"`
Title string `json:"title" table:"title,truncate"`
AuthorName string `json:"author_name"`
Original bool `json:"original"`
Duration int64 `json:"duration"`
PlayURL string `json:"play_url"`
Cover string `json:"cover"`
VideoCount int64 `json:"video_count"`
URL string `json:"url"`
}
Sound is a music page header, addressed by its numeric id.
type Source ¶
type Source interface {
VideoByID(ctx context.Context, author, id string) (Video, error)
UserByHandle(ctx context.Context, handle string) (User, error)
Posts(ctx context.Context, handle string, limit int, cursor string) ([]Video, error)
HashtagByName(ctx context.Context, name string) (Hashtag, error)
HashtagVideos(ctx context.Context, challengeID string, limit int) ([]Video, error)
SoundByID(ctx context.Context, slug, id string) (Sound, error)
SoundVideos(ctx context.Context, musicID string, limit int) ([]Video, error)
Comments(ctx context.Context, videoID, author string, limit int) ([]Comment, error)
Related(ctx context.Context, videoID string, limit int) ([]Video, error)
Search(ctx context.Context, keyword string, limit int) ([]SearchHit, error)
Trending(ctx context.Context, limit int) ([]Video, error)
}
Source is the slice of the client the walk depends on. *Client satisfies it. Tests inject a fake to run the walk offline and deterministically.
type Summary ¶
type Summary struct {
NodesByKind map[string]int
EdgesByType map[string]int
WalledEdges map[string]int
Errors map[string]int
Requests int
NodesEmitted int
Walled bool
StopReason string
}
Summary reports what a walk reached and why it stopped.
type User ¶
type User struct {
ID string `json:"id"`
UniqueID string `json:"unique_id" kit:"id"`
Nickname string `json:"nickname"`
SecUID string `json:"sec_uid"`
Signature string `json:"signature" kit:"body" table:"signature,truncate"`
Verified bool `json:"verified"`
Private bool `json:"private"`
Region string `json:"region"`
FollowerCount int64 `json:"follower_count"`
FollowingCount int64 `json:"following_count"`
HeartCount int64 `json:"heart_count"`
VideoCount int64 `json:"video_count"`
FriendCount int64 `json:"friend_count"`
Avatar string `json:"avatar"`
URL string `json:"url"`
}
User is a public profile, addressed by its @handle.
type Video ¶
type Video struct {
ID string `json:"id" kit:"id"`
Desc string `json:"desc" kit:"body" table:"desc,truncate"`
CreateTime int64 `json:"create_time"`
Author string `json:"author"`
AuthorID string `json:"author_id"`
AuthorSecUID string `json:"author_sec_uid"`
MusicID string `json:"music_id"`
MusicTitle string `json:"music_title" table:"music_title,truncate"`
MusicAuthor string `json:"music_author"`
Challenges []string `json:"challenges"`
Duration int64 `json:"duration"`
Cover string `json:"cover"`
PlayAddr string `json:"play_addr"`
DownloadAddr string `json:"download_addr"`
Width int64 `json:"width"`
Height int64 `json:"height"`
DiggCount int64 `json:"digg_count"`
CommentCount int64 `json:"comment_count"`
PlayCount int64 `json:"play_count"`
CollectCount int64 `json:"collect_count"`
URL string `json:"url"`
}
Video is a single post with its author, sound, hashtags, and counters.