b00p

command module
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Apr 18, 2026 License: MIT Imports: 1 Imported by: 0

README

b00p

CLI parser and content downloader for boosty.to. Downloads posts, images, videos, comments. Can also be used as a Go library.

Installation

go install github.com/wpt/b00p@latest

Or from source:

git clone https://github.com/wpt/b00p.git
cd b00p
go build -o b00p .

Quick Start

  1. Log in to boosty.to in your browser
  2. Open DevTools (F12) → Application → Cookies → https://boosty.to
  3. Copy the values of auth cookie — it contains a JSON object with accessToken and refreshToken
  4. Create auth.json:
cp auth.json.example auth.json

Paste your tokens:

{
  "accessToken": "paste_access_token_here",
  "refreshToken": "paste_refresh_token_here"
}

Tokens auto-refresh on 401. auth.json is in .gitignore.

  1. Run:
# Blog statistics
b00p stat --blog username

# Download all accessible posts
b00p download --blog username

# Download a single post
b00p download --url "https://boosty.to/username/posts/post-id"

Commands

stat

Shows subscription info and blog statistics.

b00p stat --blog coolblogger
=== Who Is Me ===
  Blog:   coolblogger
  Tier:   Supporter
  Price:  300 RUB
  Status: Active

=== Blog: coolblogger ===
  Total posts:  84
  Accessible:   71
  Locked:       13
download

Downloads posts with media.

# All accessible posts
b00p download --blog username

# Single post by URL
b00p download --url "https://boosty.to/username/posts/post-id"

# With markdown and comments
b00p download --blog username --md --comments

# Re-download everything (ignore state)
b00p download --blog username --force

# Custom directory name format
b00p download --blog username --format "{date:ymd}_{title}"

# Download external videos (YouTube, VK) via yt-dlp
b00p download --blog username --download-external

# Concurrent downloads (3 posts at a time)
b00p download --blog username --workers 3
sync

Smart sync: checks for updates, shows a diff, asks for confirmation before applying.

# Check for new posts, edits, new comments
b00p download --blog username --sync

# Also validate video file sizes
b00p download --blog username --sync --check-media

# Verify all expected files exist on disk
b00p download --blog username --sync --check-files

Example output:

Syncing username...
  [NEW] New post title
  [UNLOCKED] Previously locked post (was locked, now accessible)
  [UPDATED] Edited post (post edited)
  [COMMENTS] Post with discussion (comments: 5 → 8)
  [LOCKED] Downgraded post (was accessible, now locked)

Sync summary:
  1 new posts
  1 unlocked posts
  1 updated posts
  1 comments updated
  1 locked (data preserved)
  79 no changes

Apply changes? [y/N]

Sync detects:

  • NEW — post not previously downloaded
  • UNLOCKED — post was locked, now accessible (subscription upgraded)
  • UPDATED — post was edited by the author (updatedAt changed)
  • COMMENTS — new comments added
  • VIDEO_MISMATCH — local video file size differs from remote (with --check-media)
  • FILES_MISSING — expected files missing on disk (with --check-files)
  • LOCKED — post was accessible, now locked (subscription downgraded). Data on disk is preserved.

Flags

Flag Default Description
--auth auth.json Path to token file
-o, --output output Output directory
--md false Generate markdown file with frontmatter (includes tier/price)
--comments false Download comments
--download-external false Download external videos via yt-dlp
--force false Ignore state, re-download everything
--sync false Smart sync with diff and confirmation
--check-media false With --sync: validate video file sizes
--check-files false With --sync: verify post.json, comments.json, post.md exist on disk
--format {date}_{title} Post directory name format
--workers 1 Number of concurrent downloads

Directory Name Format

Variables for --format:

Variable Example Description
{title} Stream #87 Post title
{date} 2026-03-13 Publish date (ISO)
{date:ymd} 20260313 Date with custom format
{date:d.m.y} 13.03.2026 y=year, m=month, d=day
{id} e24c0343-... Post UUID

Output Structure

output/username/
  _state.json                              # downloaded posts tracker
  2026-03-13_Post Title/
    post.json                              # post data (always)
    post.md                                # markdown (with --md)
    comments.json                          # comments (with --comments)
    image_001.jpg                          # images
    video_001.mp4                          # native videos (best MP4)

State Tracking

b00p tracks downloaded posts in _state.json. Each entry includes:

  • Post title and directory name
  • Download timestamp
  • updatedAt and comment count (for sync diffing)
  • Price and subscription tier required
  • Locked status

On subsequent runs, only new posts are downloaded. Locked posts are not saved to state — after upgrading your subscription, they are automatically downloaded on the next run. Downgraded posts keep their data on disk and are marked as locked.

Reliability

  • Retry with backoff: all network operations retry 3 times with increasing delays (5s / 15s / 30s)
  • Integrity check: existing non-empty files are skipped, 0-byte partial files are cleaned up
  • Incremental state saves: state is written after each post, so interrupted downloads resume where they left off
  • Spinner: animated progress indicator with file size during downloads (⠹ video_001.mp4 45.2 MB / 1.2 GB (3.7%))
  • Clear error messages: expired tokens show instructions to update auth.json

External Videos

Posts may contain embedded videos from YouTube, VK, OK. By default b00p only saves the link in markdown. With --download-external it downloads them via yt-dlp:

pip install yt-dlp
b00p download --blog username --download-external

Library Usage

import (
    "github.com/wpt/b00p/pkg/boosty"
    "github.com/wpt/b00p/pkg/parser"
)

// Create client
tokens, _ := boosty.LoadTokens("auth.json")
client := boosty.NewClient(tokens, "auth.json")

// Fetch a post
var post boosty.Post
client.GetJSON(boosty.PostURL("blogname", "post-id"), &post)

// Parse content
parsed := parser.ParseBlocks(post.Data)
for _, text := range parsed.TextParts {
    fmt.Println(text)
}
for _, media := range parsed.Media {
    fmt.Println(media.Type, media.URL)
}

// Access tier info
if post.SubscriptionLevel != nil {
    fmt.Println("Tier:", post.SubscriptionLevel.Name)
}
fmt.Println("Price:", post.Price)

Tests

go test ./... -v

License

MIT

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
pkg

Jump to

Keyboard shortcuts

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